Elasticsearch进阶篇-DSL

目录

DSL查询

[1 快速入门](#1 快速入门)

[2 DSL 查询分类](#2 DSL 查询分类)

[2.1 叶子查询](#2.1 叶子查询)

[2.1.1 全文检索查询](#2.1.1 全文检索查询)

语法

举例

[2.1.2 精准查询](#2.1.2 精准查询)

[term 语法](#term 语法)

[term 示例](#term 示例)

[range 语法](#range 语法)

[range 示例](#range 示例)

[2.2 复合查询](#2.2 复合查询)

[2.2.1 bool查询](#2.2.1 bool查询)

举例

[2.3 排序](#2.3 排序)

语法

示例

[2.4 分页](#2.4 分页)

[2.4.1 基础分页](#2.4.1 基础分页)

示例

[2.4.2 深度分页](#2.4.2 深度分页)

[2.4.3 总结](#2.4.3 总结)

[2.5 高亮](#2.5 高亮)

[2.5.1 语法](#2.5.1 语法)

[2.5.2 示例](#2.5.2 示例)

[2.5.3 注意](#2.5.3 注意)

[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,因此其查询语句如下:

bash 复制代码
# 无条件查询
GET /items/_search
{
  "query": {
    "match_all": {}
  }
}

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

执行结果如下:

bash 复制代码
{
  "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为例

bash 复制代码
GET /{索引库名}/_search
{
  "query": {
    "match": {
      "字段名": "搜索条件"
    }
  }
}

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

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

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

  • id

  • price

  • 城市

  • 地名

  • 人名

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

term 语法

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

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

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

  • gte:大于等于

  • gt:大于

  • lte:小于等于

  • lt:小于

range 示例
bash 复制代码
# 需求:搜索结果在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查询的语法如下:

bash 复制代码
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,那么可以这样写:

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

2.3 排序

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

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

2.4 分页

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

2.4.1 基础分页

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

  • from:从第几个文档开始

  • size:总共查询几个文档

类似于mysql中的limit ?, ?

示例
bash 复制代码
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 语法
bash 复制代码
GET /{索引库名}/_search
{
  "query": {
    "match": {
      "搜索字段": "搜索关键字"
    }
  },
  "highlight": {
    "fields": {
      "高亮字段名称": {
        "pre_tags": "<em>",
        "post_tags": "</em>"
      }
    }
  }
}
2.5.2 示例
bash 复制代码
# 高亮
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:高亮条件

相关推荐
onkel in blog13 分钟前
【Docker】Docker Compose方式搭建分布式协调服务(Zookeeper)集群
分布式·docker·zookeeper
小伍_Five1 小时前
spark数据处理练习题详解【下】
java·大数据·spark·scala
你的坚持终将美好,1 小时前
elasticsearch kibana ik 各版本下载
大数据·elasticsearch·搜索引擎
小小工匠2 小时前
架构思维:构建高并发扣减服务_分布式无主架构
分布式·架构·分布式无主架构
Pluto_CSND2 小时前
hbase shell的常用命令
大数据·数据库·hbase
白熊1882 小时前
【通用智能体】Serper API 详解:搜索引擎数据获取的核心工具
人工智能·搜索引擎·大模型
API_technology3 小时前
阿里巴巴 1688 数据接口开发指南:构建自动化商品详情采集系统
大数据·运维·数据挖掘·自动化
hong_zc4 小时前
服务端高并发分布式结构演进之路
分布式
L耀早睡5 小时前
Spark缓存
大数据·数据库·spark