Elasticsearch进阶篇-DSL

目录

DSL查询

1 快速入门

2 DSL 查询分类

2.1 叶子查询

2.1.1 全文检索查询

语法

举例

2.1.2 精准查询

term 语法

term 示例

range 语法

range 示例

2.2 复合查询

2.2.1 bool查询

举例

2.3 排序

语法

示例

2.4 分页

2.4.1 基础分页

示例

2.4.2 深度分页

2.4.3 总结

2.5 高亮

2.5.1 语法

2.5.2 示例

2.5.3 注意

3. 总结


今天,我们来研究下elasticsearch的数据搜索功能。Elasticsearch提供了基于JSON的DSL(Domain Specific Language)语句来定义查询条件,其JavaAPI就是在组织DSL条件。

因此,我们先学习DSL的查询语法,然后再基于DSL来对照学习JavaAPI,就会事半功倍。

DSL查询

Elasticsearch的查询可以分为两大类:

  • 叶子查询(Leaf query clauses):一般是在特定的字段里查询特定值,属于简单查询,很少单独使用。

  • 复合查询(Compound query clauses):以逻辑方式组合多个叶子查询或者更改叶子查询的行为方式。

1 快速入门

我们依然在Kibana的DevTools中学习查询的DSL语法。首先来看查询的语法结构:

GET /{索引库名}/_search 
{ 
   "query": {
      "查询类型": { 
            // .. 查询条件 
         }
     } 
}

说明:

  • GET /{索引库名}/_search:其中的_search是固定路径,不能修改

例如,我们以最简单的无条件查询为例,无条件查询的类型是:match_all,因此其查询语句如下:

# 无条件查询
GET /items/_search
{
  "query": {
    "match_all": {}
  }
}

由于match_all无条件,所以条件位置不写即可。

执行结果如下:

{
  "took" : 9,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 10000,
      "relation" : "gte"
    },
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "items",
        "_type" : "_doc",
        "_id" : "317578",
        "_score" : 1.0,
        "_source" : {
          "id" : "317578",
          "name" : "RIMOWA 21寸托运箱拉杆箱 SALSA AIR系列果绿色 820.70.36.4",
          "price" : 28900,
          "image" : "https://m.360buyimg.com/mobilecms/s720x720_jfs/t6934/364/1195375010/84676/e9f2c55f/597ece38N0ddcbc77.jpg!q70.jpg.webp",
          "category" : "拉杆箱",
          "brand" : "RIMOWA",
          "sold" : 0,
          "commentCount" : 0,
          "isAD" : false,
          "updateTime" : 1683342377000
        }
      },
      {
        "_index" : "items",
        "_type" : "_doc",
        "_id" : "317580",
        "_score" : 1.0,
        "_source" : {
          "id" : "317580",
          "name" : "RIMOWA 26寸托运箱拉杆箱 SALSA AIR系列果绿色 820.70.36.4",
          "price" : 28600,
          "image" : "https://m.360buyimg.com/mobilecms/s720x720_jfs/t6934/364/1195375010/84676/e9f2c55f/597ece38N0ddcbc77.jpg!q70.jpg.webp",
          "category" : "拉杆箱",
          "brand" : "RIMOWA",
          "sold" : 0,
          "commentCount" : 0,
          "isAD" : false,
          "updateTime" : 1696644279000
        }
      },
      {
        "_index" : "items",
        "_type" : "_doc",
        "_id" : "546872",
        "_score" : 1.0,
        "_source" : {
          "id" : "546872",
          "name" : "博兿(BOYI)拉杆包男23英寸大容量旅行包户外手提休闲拉杆袋 BY09186黑灰色",
          "price" : 27500,
          "image" : "https://m.360buyimg.com/mobilecms/s720x720_jfs/t3301/221/3887995271/90563/bf2cadb/57f9fbf4N8e47c225.jpg!q70.jpg.webp",
          "category" : "拉杆箱",
          "brand" : "博兿",
          "sold" : 0,
          "commentCount" : 0,
          "isAD" : false,
          "updateTime" : 1556640000000
        }
      },
      {
        "_index" : "items",
        "_type" : "_doc",
        "_id" : "561178",
        "_score" : 1.0,
        "_source" : {
          "id" : "561178",
          "name" : "RIMOWA 30寸托运箱拉杆箱 SALSA AIR系列果绿色 820.70.36.4",
          "price" : 13000,
          "image" : "https://m.360buyimg.com/mobilecms/s720x720_jfs/t6934/364/1195375010/84676/e9f2c55f/597ece38N0ddcbc77.jpg!q70.jpg.webp",
          "category" : "拉杆箱",
          "brand" : "RIMOWA",
          "sold" : 0,
          "commentCount" : 0,
          "isAD" : false,
          "updateTime" : 1696644294000
        }
      },
      {
        "_index" : "items",
        "_type" : "_doc",
        "_id" : "577967",
        "_score" : 1.0,
        "_source" : {
          "id" : "577967",
          "name" : "莎米特SUMMIT 旅行拉杆箱28英寸PC材质大容量旅行行李箱PC154 黑色",
          "price" : 71300,
          "image" : "https://m.360buyimg.com/mobilecms/s720x720_jfs/t30454/163/719393962/79149/13bcc06a/5bfca9b6N493202d2.jpg!q70.jpg.webp",
          "category" : "拉杆箱",
          "brand" : "莎米特",
          "sold" : 0,
          "commentCount" : 0,
          "isAD" : false,
          "updateTime" : 1556640000000
        }
      },
      {
        "_index" : "items",
        "_type" : "_doc",
        "_id" : "584382",
        "_score" : 1.0,
        "_source" : {
          "id" : "584382",
          "name" : "美旅AmericanTourister拉杆箱 商务男女超轻PP行李箱时尚大容量耐磨飞机轮旅行箱 25英寸海关锁DL7灰色",
          "price" : 36600,
          "image" : "https://m.360buyimg.com/mobilecms/s720x720_jfs/t1/22734/21/2036/130399/5c18af2aEab296c01/7b148f18c6081654.jpg!q70.jpg.webp",
          "category" : "拉杆箱",
          "brand" : "美旅箱包",
          "sold" : 0,
          "commentCount" : 0,
          "isAD" : false,
          "updateTime" : 1556640000000
        }
      },
      {
        "_index" : "items",
        "_type" : "_doc",
        "_id" : "584387",
        "_score" : 1.0,
        "_source" : {
          "id" : "584387",
          "name" : "美旅AmericanTourister拉杆箱 商务男女超轻PP行李箱时尚大容量耐磨飞机轮旅行箱 29英寸海关锁DL7灰色",
          "price" : 16200,
          "image" : "https://m.360buyimg.com/mobilecms/s720x720_jfs/t1/22734/21/2036/130399/5c18af2aEab296c01/7b148f18c6081654.jpg!q70.jpg.webp",
          "category" : "拉杆箱",
          "brand" : "美旅箱包",
          "sold" : 0,
          "commentCount" : 0,
          "isAD" : false,
          "updateTime" : 1556640000000
        }
      },
      {
        "_index" : "items",
        "_type" : "_doc",
        "_id" : "584391",
        "_score" : 1.0,
        "_source" : {
          "id" : "584391",
          "name" : "美旅AmericanTourister拉杆箱 商务男女超轻PP行李箱时尚大容量耐磨飞机轮旅行箱 20英寸海关锁DL7灰色",
          "price" : 29900,
          "image" : "https://m.360buyimg.com/mobilecms/s720x720_jfs/t1/22734/21/2036/130399/5c18af2aEab296c01/7b148f18c6081654.jpg!q70.jpg.webp",
          "category" : "拉杆箱",
          "brand" : "美旅箱包",
          "sold" : 0,
          "commentCount" : 0,
          "isAD" : false,
          "updateTime" : 1556640000000
        }
      },
      {
        "_index" : "items",
        "_type" : "_doc",
        "_id" : "584392",
        "_score" : 1.0,
        "_source" : {
          "id" : "584392",
          "name" : "美旅AmericanTourister拉杆箱 商务男女超轻PP行李箱时尚大容量耐磨飞机轮旅行箱 29英寸海关锁DL7灰色",
          "price" : 17000,
          "image" : "https://m.360buyimg.com/mobilecms/s720x720_jfs/t1/22734/21/2036/130399/5c18af2aEab296c01/7b148f18c6081654.jpg!q70.jpg.webp",
          "category" : "拉杆箱",
          "brand" : "美旅箱包",
          "sold" : 0,
          "commentCount" : 0,
          "isAD" : false,
          "updateTime" : 1696644299000
        }
      },
      {
        "_index" : "items",
        "_type" : "_doc",
        "_id" : "584394",
        "_score" : 1.0,
        "_source" : {
          "id" : "584394",
          "name" : "美旅AmericanTourister拉杆箱 商务男女超轻PP行李箱时尚大容量耐磨飞机轮旅行箱 25英寸海关锁DL7灰色",
          "price" : 79400,
          "image" : "https://m.360buyimg.com/mobilecms/s720x720_jfs/t1/22734/21/2036/130399/5c18af2aEab296c01/7b148f18c6081654.jpg!q70.jpg.webp",
          "category" : "拉杆箱",
          "brand" : "美旅箱包",
          "sold" : 0,
          "commentCount" : 0,
          "isAD" : false,
          "updateTime" : 1556640000000
        }
      }
    ]
  }
}

你会发现虽然是match_all,但是响应结果中并不会包含索引库中的所有文档,而是仅有10条。这是因为处于安全考虑,elasticsearch设置了默认的查询页数。

2 DSL 查询分类

DSL 查询可以分为两大类:
• 叶子查询( Leaf query clauses ):一般是在特定的字段里查询特定值,属于简单查询,很少单独使用。
• 复合查询( Compound query clauses ):以逻辑方式组合多个叶子查询或者更改叶子查询的行为方式。
在查询以后,还可以对查询的结果做处理,包括:
• 排序:按照 1 个或多个字段值做排序
• 分页:根据 from 和 size 做分页,类似 MySQL
• 高亮:对搜索结果中的关键字添加特殊样式,使其更加醒目
• 聚合:对搜索结果做数据统计以形成报表

2.1 叶子查询

这里列举一些常见的,例如:

  • 全文检索查询(Full Text Queries):利用分词器对用户输入搜索条件先分词,得到词条,然后再利用倒排索引搜索词条。例如:

    • match

    • multi_match

  • 精确查询(Term-level queries):不对用户输入搜索条件分词,根据字段内容精确值匹配。但只能查找keyword、数值、日期、boolean类型的字段。例如:

    • ids

    • term

    • range

  • 地理坐标查询用于搜索地理位置,搜索方式很多,例如:

    • geo_bounding_box:按矩形搜索

    • geo_distance:按点和半径搜索

  • ...略

2.1.1 全文检索查询
语法

以全文检索中的match为例

GET /{索引库名}/_search
{
  "query": {
    "match": {
      "字段名": "搜索条件"
    }
  }
}

 与match类似的还有multi_match,区别在于可以同时对多个字段搜索,而且多个字段都要满足,

GET /{索引库名}/_search
{
  "query": {
    "multi_match": {
      "query": "搜索条件",
      "fields": ["字段1", "字段2"]
    }
  }
}
举例
# match所有
# 需求:搜索商品名称含脱脂牛奶
GET /items/_search
{
  "query": {
    "match": {
      "name": "脱脂牛奶"
    }
  }
}
GET /items/_search
{
  "query": {
    "multi_match": {
      "query": "脱脂牛奶",
      "fields": ["name","brand"]
    }
  }
}
2.1.2 精准查询

精确查询,英文是Term-level query,顾名思义,词条级别的查询。也就是说不会对用户输入的搜索条件再分词,而是作为一个词条,与搜索的字段内容精确值匹配。因此推荐查找keyword、数值、日期、boolean类型的字段。例如:

  • id

  • price

  • 城市

  • 地名

  • 人名

等等,作为一个整体才有含义的字段。

term 语法

term查询为例,其语法如下:

GET /{索引库名}/_search
{
  "query": {
    "term": {
      "字段名": {
        "value": "搜索条件"
      }
    }
  }
}
term 示例
# 需求:搜索品牌名称是德亚
GET /items/_search
{
  "query": {
    "term": {
      "brand": {
        "value": "德亚"
      }
    }
  }
}
range 语法
GET /{索引库名}/_search
{
  "query": {
    "range": {
      "字段名": {
        "gte": {最小值},
        "lte": {最大值}
      }
    }
  }
}

range是范围查询,对于范围筛选的关键字有:

  • gte:大于等于

  • gt:大于

  • lte:小于等于

  • lt:小于

range 示例
# 需求:搜索结果在500到1000的
GET /items/_search
{
  "query": {
    "range": {
      "price": {
        "gte": 50000,
        "lte": 100000
      }
    }
  }
}

2.2 复合查询

复合查询大致可以分为两类:

  • 第一类:基于逻辑运算组合叶子查询,实现组合条件,例如

    • bool

  • 第二类:基于某种算法修改查询时的文档相关性算分,从而改变文档排名。例如:

    • function_score

    • dis_max

注:我们这里只讲解bool查询

2.2.1 bool查询

bool查询,即布尔查询。就是利用逻辑运算来组合一个或多个查询子句的组合。bool查询支持的逻辑运算有:

  • must:必须匹配每个子查询,类似“与”

  • should:选择性匹配子查询,类似“或”

  • must_not:必须不匹配,不参与算分,类似“非”

  • filter:必须匹配,不参与算分

bool查询的语法如下:

GET /items/_search
{
  "query": {
    "bool": {
      "must": [
        {"match": {"name": "手机"}}
      ],
      "should": [
        {"term": {"brand": { "value": "vivo" }}},
        {"term": {"brand": { "value": "小米" }}}
      ],
      "must_not": [
        {"range": {"price": {"gte": 2500}}}
      ],
      "filter": [
        {"range": {"price": {"lte": 1000}}}
      ]
    }
  }
}

出于性能考虑,与搜索关键字无关的查询尽量采用must_not或filter逻辑运算,避免参与相关性算分。

举例

我们要搜索手机,但品牌必须是华为,价格必须是900~1599,那么可以这样写:

GET /items/_search
{
  "query": {
    "bool": {
      "must": [
        {"match": {"name": "手机"}}
      ],
      "filter": [
        {"term": {"brand": { "value": "华为" }}},
        {"range": {"price": {"gte": 90000, "lt": 159900}}}
      ]
    }
  }
}

2.3 排序

elasticsearch默认是根据相关度算分(_score)来排序,但是也支持自定义方式对搜索结果排序。不过分词字段无法排序,能参与排序字段类型有:keyword类型、数值类型、地理坐标类型、日期类型等。

语法
GET /indexName/_search
{
  "query": {
    "match_all": {}
  },
  "sort": [
    {
      "排序字段": {
        "order": "排序方式asc和desc"
      }
    }
  ]
}
示例
# 排序查询,排序没有打分,先按第一个字段排序,仅当第一个字段值相同时,才会按第二个字段排序。如果第一个字段的值完全不同,后续字段不会影响最终顺序。
GET /items/_search
{
  "query": {
    "match_all": {}
  },
  "sort": [
    {
      "sold": "desc"
    },
    {
      "price": "asc"
    }
  ]
}

2.4 分页

elasticsearch 默认情况下只返回top10的数据。而如果要查询更多数据就需要修改分页参数了。

2.4.1 基础分页

elasticsearch中通过修改fromsize参数来控制要返回的分页结果:

  • from:从第几个文档开始

  • size:总共查询几个文档

类似于mysql中的limit ?, ?

示例
GET /items/_search
{
  "query": {
    "match_all": {}
  },
  "from": 0, // 分页开始的位置,默认为0
  "size": 10,  // 每页文档数量,默认10
  "sort": [
    {
      "price": {
        "order": "desc"
      }
    }
  ]
}
2.4.2 深度分页

elasticsearch的数据一般会采用分片存储,也就是把一个索引中的数据分成N份,存储到不同节点上。这种存储方式比较有利于数据扩展,但给分页带来了一些麻烦。

针对深度分页,elasticsearch提供了两种解决方案:

  • search after:分页时需要排序,原理是从上一次的排序值开始,查询下一页数据。官方推荐使用的方式。

  • scroll:原理将排序后的文档id形成快照,保存下来,基于快照做分页。官方已经不推荐使用。

2.4.3 总结

大多数情况下,我们采用普通分页就可以了。查看百度、京东等网站,会发现其分页都有限制。例如百度最多支持77页,每页不足20条。京东最多100页,每页最多60条。

因此,一般我们采用限制分页深度的方式即可,无需实现深度分页。

2.5 高亮

高亮显示:就是在搜索结果中把搜索关键字突出显示。

2.5.1 语法
GET /{索引库名}/_search
{
  "query": {
    "match": {
      "搜索字段": "搜索关键字"
    }
  },
  "highlight": {
    "fields": {
      "高亮字段名称": {
        "pre_tags": "<em>",
        "post_tags": "</em>"
      }
    }
  }
}
2.5.2 示例
# 高亮
GET /items/_search
{
  "query": {
    "match": {
      "name": "脱脂牛奶"
    }
  },
  "highlight": {
    "fields": {
      "name": { 
        "pre_tags": "<em>", //默认em,所以可以不写
        "post_tags": "</em>"
      }
    }
  }
}
2.5.3 注意
  • 搜索必须有查询条件,而且是全文检索类型的查询条件,例如match

  • 参与高亮的字段必须是text类型的字段

  • 默认情况下参与高亮的字段要与搜索字段一致,除非添加:required_field_match=false

3. 总结

查询的DSL是一个大的JSON对象,包含下列属性:

  • query:查询条件

  • fromsize:分页条件

  • sort:排序条件

  • highlight:高亮条件

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值