> 技术文档 > Elasticsearch 高级查询语法 Query DSL 实战指南

Elasticsearch 高级查询语法 Query DSL 实战指南

目录

1、DSL 概述

1.1 DSL按照查询的结构层次划分

1.2 DSL按照检索功能的用途和特性划分

1.3 示例数据准备

2、match_all ——匹配所有文档

3、精确匹配

3.1 term——单字段精确匹配查询

3.2 terms——多值精确匹配

3.3 range——范围查询

3.4 exists——是否存在查询

3.5 ids——根据一组id查询

3.6 Prefix Query - 前缀匹配

3.7 wildcard——通配符匹配

3.8 regexp——正则匹配查询

3.9 fuzzy——支持编辑距离的模糊查询

3.10 term set——用于解决多值字段中的文档匹配问题

4. 全文检索

4.1 match——分词查询

4.2 multi_match——多字段查询

4.3 match_phrase短语查询

4.4 match_phrase_prefix——短语前缀匹配(严格顺序) 

4.5 match_bool_prefix——短语前缀匹配(无顺序) 

4.6 query_string——支持与或非表达式的查询

4.7 simple_query_string——更安全的 query_string 替代品

4.8 interval—— 高级文本匹配工具

5. bool query布尔查询

6. highlight高亮

7. 地理空间位置查询

8. ElasticSearch8.x 向量检索


1、DSL 概述

ES中提供了一种强大的检索数据方式,这种检索方式称之为Query DSL(Domain Specified Language 领域专用语言) , Query DSL是利用Rest API传递JSON格式的请求体(RequestBody)数据与ES进行交互,这种方式的丰富查询语法让ES检索变得更强大,更简洁。

官方文档: Query DSL | Elasticsearch Guide [8.14] | Elastic

1.1 DSL按照查询的结构层次划分

1.2 DSL按照检索功能的用途和特性划分

1.3 示例数据准备

DELETE /employeePUT /employee{ \"settings\": { \"number_of_shards\": 1, \"number_of_replicas\": 1 }, \"mappings\": { \"properties\": { \"name\": { \"type\": \"keyword\" }, \"sex\": { \"type\": \"integer\" }, \"age\": { \"type\": \"integer\" }, \"address\": { \"type\": \"text\", \"analyzer\": \"ik_max_word\", \"fields\": { \"keyword\": { \"type\": \"keyword\" } } }, \"remark\": { \"type\": \"text\", \"analyzer\": \"ik_smart\", \"fields\": { \"keyword\": { \"type\": \"keyword\" } } } } }}POST /employee/_bulk{\"index\":{\"_index\":\"employee\",\"_id\":\"1\"}}{\"name\":\"张三\",\"sex\":1,\"age\":25,\"address\":\"广州富星商业大厦\",\"remark\":\"java developer\"}{\"index\":{\"_index\":\"employee\",\"_id\":\"2\"}}{\"name\":\"李四\",\"sex\":1,\"age\":28,\"address\":\"广州塔\",\"remark\":\"java assistant\"}{\"index\":{\"_index\":\"employee\",\"_id\":\"3\"}}{\"name\":\"王五\",\"sex\":0,\"age\":26,\"address\":\"番禺万民城\",\"remark\":\"php developer\"}{\"index\":{\"_index\":\"employee\",\"_id\":\"4\"}}{\"name\":\"赵六\",\"sex\":0,\"age\":22,\"address\":\"番禺南村万博\",\"remark\":\"python assistant\"}{\"index\":{\"_index\":\"employee\",\"_id\":\"5\"}}{\"name\":\"拐脚七\",\"sex\":0,\"age\":19,\"address\":\"江门万达广场\",\"remark\":\"java architect assistant\"}{\"index\":{\"_index\":\"employee\",\"_id\":\"6\"}}{\"name\":\"三八\",\"sex\":1,\"age\":32,\"address\":\"台山浪琴湾\",\"remark\":\"java architect\"}{\"index\":{\"_index\":\"employee\",\"_id\":\"7\"}}{\"name\":\"九天\",\"sex\":1,\"age\":35,\"address\":\"广州白云山\",\"remark\":\"go architect\"}

2、match_all ——匹配所有文档

match_all查询是一个特殊的查询类型,它用于匹配索引中的所有文档,而不考虑任何特定的查询条件。

基本语法

GET //_search{ \"query\": { \"match_all\": {} }}

高级用法

例如,如果您想要返回索引中的前10个文档,并且按照文档的评分进行排序,您可以使用以下查询:

GET //_search{ \"query\": { \"match_all\": {} }, \"size\": 10, \"sort\": [ {\"_score\": {\"order\": \"desc\"}} ]}
  • size 返回指定条数

_source的用法

#不查看源数据,仅查看元字段GET //_search{ \"query\": { \"match_all\": {} }, \"_source\": false}# 返回指定字段GET //_search{ \"query\": { \"match_all\": {} }, \"_source\": [\"field1\",\"field2\"]}#只看以obj.开头的字段GET //_search{ \"query\": { \"match_all\": {} }, \"_source\": \"obj.*\"}

from&size分页查询

GET /employee/_search{ \"query\": { \"match_all\": {} }, \"from\": 0, \"size\": 5 }

sort 指定字段排序

# 根据age排序GET /employee/_search{ \"query\": { \"match_all\": {} }, \"sort\": [ { \"age\": \"desc\" } ]}# 排序的同时进行分页GET /employee/_search{ \"query\": { \"match_all\": {} }, \"sort\": [ { \"age\": \"desc\" } ], \"from\": 2, \"size\": 5}

3、精确匹配

精确匹配是指的是搜索内容不经过文本分析直接用于文本匹配,这个过程类似于数据库的SQL查询,搜索的对象大多是索引的非text类型字段。此类检索主要应用于结构化数据,如ID、状态和标签等。

3.1 term——单字段精确匹配查询

term检索主要应用于单字段精准匹配的场景。在实战过程中,需要避免将term检索应用于text类型的检索。进一步说,term检索针对的是非text类型,用于text类型时并不会报错,但检索结果一般会达不到预期。

基本语法

在Elasticsearch 8.x中,term查询用于执行精确匹配查询,它适用于未经过分词处理的keyword字段类型。term查询的基本语法如下:

GET /{index_name}/_search{ \"query\": { \"term\": { \"{field.keyword}\": { \"value\": \"your_exact_value\" } } }}

这里的{index_name}是你要查询的索引名称,{field.keyword}是你要匹配的字段名称,.keyword后缀表示该字段是一个keyword类型,用于存储精确匹配的数据。\"value\"是你要精确匹配的值。

示例

对bool,日期,数字,结构化的文本可以利用term做精确匹配

# 查询姓名为张三的员工信息GET /employee/_search{ \"query\":{ \"term\": { \"address\": { \"value\": \"番禺\" } } }}# 采用term精确查询, 查询字段映射类型为keywordGET /employee/_search{ \"query\":{ \"term\": { \"address.keyword\": { \"value\": \"番禺万民城\" } } }}

注意:最好不要在term查询的字段中使用text字段,因为text字段会被分词,这样做既没有意义,还很有可能什么也查不到。

term处理多值字段(数组)时,term查询是包含,不是等于。

POST /people/_bulk{\"index\":{\"_id\":1}}{\"name\":\"小明\",\"interest\":[\"跑步\",\"篮球\"]}{\"index\":{\"_id\":2}}{\"name\":\"小红\",\"interest\":[\"跳舞\",\"画画\"]}{\"index\":{\"_id\":3}}{\"name\":\"小丽\",\"interest\":[\"跳舞\",\"唱歌\",\"跑步\"]}POST /people/_search{ \"query\": { \"term\": { \"interest.keyword\": { \"value\": \"跑步\" } } }}

3.2 terms——多值精确匹配

terms检索主要应用于多值精准匹配场景,它允许用户在单个查询中指定多个词条来进行精确匹配。这种查询方式适合从文档中查找包含多个特定值的字段,例如筛选出具有多个特定标签或状态的项目。而terms检索是针对未分析的字段进行精确匹配的,因此它在处理关键词、数字、日期等结构化数据时表现良好。

基本语法

在Elasticsearch 8.x中,进行多字段精确匹配时,可以使用terms查询。terms查询允许你指定一个字段,并匹配该字段中的多个精确值。

基本语法如下:

GET //_search{ \"query\": { \"terms\": { \"\": [ \"value1\", \"value2\", \"value3\", ... ] } }}
  •  是你想要查询的索引名称。
  •  是你想要对其执行terms查询的字段名。

  • 方括号内的值列表是你希望在查询中匹配的字段值。

示例

POST /employee/_search{ \"query\": { \"terms\": { \"remark.keyword\": [\"java assistant\", \"java architect\"] } }}

3.3 range——范围查询

range检索是Elasticsearch中一种针对指定字段值在给定范围内的文档的检索类型。这种查询适合对数字、日期或其他可排序数据类型的字段进行范围筛选。range检索支持多种比较操作符,如大于(gt)、大于等于(gte)、小于(lt)和小于等于(lte)等,可以实现灵活的区间查询。

基本语法

在Elasticsearch 8.x版本中,range查询的基本语法如下:

GET //_search{ \"query\": { \"range\": { \"\": { \"gte\": , \"lte\": , \"gt\": , \"lt\":  } } }}
  •  是你想要查询的索引名称。
  •  是你想要对其执行range查询的字段名。
  • gte 表示大于或等于(Greater Than or Equal)。
  • lte 表示小于或等于(Less Than or Equal)。
  • gt 表示严格大于(Greater Than)。
  • lt 表示严格小于(Less Than)。
  • , , , 是指定的数值边界。

示例

  • 查询年龄在25到28的员工
POST /employee/_search{ \"query\": { \"range\": { \"age\": { \"gte\": 25, \"lte\": 28 } } }}

3.4 exists——是否存在查询

exists检索在Elasticsearch中用于筛选具有特定字段值的文档。这种查询类型适用于检查文档中是否存在某个字段,或者该字段是否包含非空值。通过使用exists检索,你可以有效地过滤掉缺少关键信息的文档,从而专注于包含所需数据的结果。应用场景包括但不限于数据完整性检查、查询特定属性的文档以及对可选字段进行筛选等。

基本语法

GET //_search{ \"query\": { \"exists\": { \"field\": \"missing_field\" } }}

示例

查询索引库中存在remark字段的文档

GET /employee/_search{ \"query\": { \"exists\": { \"field\": \"remark\" } }}

3.5 ids——根据一组id查询

IDs检索也是一种常用的Elasticsearch查询方法,它允许我们基于给定的ID组快速召回相关数据,从而实现高效的文档检索。

基本语法

在Elasticsearch 8.x中,ids查询用于返回具有指定ID列表的文档。这个查询是检索特定文档的有效方式,特别是当你已经知道具体的文档ID时。

基本语法如下:

GET //_search{ \"query\": { \"ids\": { \"values\": [\"id1\", \"id2\", \"id3\", ...] } }}

示例

GET /employee/_search{ \"query\": { \"ids\": { \"values\": [1,2] } }}

3.6 Prefix Query - 前缀匹配

这种查询不会对搜索字符串进行分词处理,用户输入的前缀将直接作为匹配条件。

默认情况下,前缀查询不会计算相关性分数,而是返回所有匹配的文档,并将它们的分数统一设为1。

实现原理

通过遍历所有倒排索引,检查每个词项是否以指定前缀开头来实现匹配。

基本用法

在Elasticsearch 8.x中,prefix查询用于查找指定字段中以特定前缀开头的文档,常用于自动补全或搜索场景,特别是当用户输入的内容可能是更长文本的起始部分时。基础语法如下:

GET //_search{ \"query\": { \"prefix\": { \"your_field_name\": { \"value\": \"your_prefix_string\" } } }}

3.7 wildcard——通配符匹配

Elasticsearch的wildcard检索是一种支持通配符匹配的查询方式,允许使用通配符表达式来匹配文档字段值。主要支持两种通配符:

  • 星号(*):匹配零个或多个任意字符
  • 问号(?):匹配单个任意字符

这种检索方式特别适合对部分已知内容的文本字段进行模糊匹配,比如文件名、产品编号等具有特定格式的字段。使用时需注意:通配符查询可能带来较大计算开销,在数据量大的场景中应谨慎使用。

基本语法如下:

GET //_search{ \"query\": { \"wildcard\": { \"your_field_name\": { \"value\": \"your_search_pattern\" } } }}

示例:

GET /employee/_search{ \"query\": { \"wildcard\": { \"address.keyword\": { \"value\": \"*万*广场\" } } }}

3.8 regexp——正则匹配查询

regexp检索是一种基于正则表达式的检索方法。虽然该检索方式的功能强大,但建议在非必要情况下避免使用,以保持查询性能的高效和稳定。

基本语法

在Elasticsearch 8.x中,regexp 查询用于在字段中执行正则表达式匹配。这个查询可以用来搜索满足特定模式的文本,并且比 wildcard 查询更加灵活和强大。

基本语法如下:

GET //_search{ \"query\": { \"regexp\": { \"your_field_name\": { \"value\": \"your_search_pattern\" } } }}

示例

GET /employee/_search{ \"query\": { \"regexp\": { \"remark\": { \"value\": \"java.*\" } } }}

3.9 fuzzy——支持编辑距离的模糊查询

fuzzy检索是一种强大的搜索功能,它能够在用户输入内容存在拼写错误或上下文不一致时,仍然返回与搜索词相似的文档。通过使用编辑距离算法来度量输入词与文档中词条的相似程度,模糊查询在保证搜索结果相关性的同时,有效地提高了搜索容错能力。

编辑距离是指从一个单词转换到另一个单词需要编辑单字符的次数。如中文集团到中威集团编辑距离就是1,只需要修改一个字符;如果fuzziness值在这里设置成2,会把编辑距离为2的东东集团也查出来。

基本语法

基本语法如下:

  • GET //_search{ \"query\": { \"fuzzy\": { \"your_field\": { \"value\": \"search_term\", \"fuzziness\": \"AUTO\", \"prefix_length\": 1 } } }}
  • fuzziness参数用于编辑距离的设置,其默认值为AUTO,支持的数值为[0,1,2]。如果值设置越界会报错。
  • prefix_length: 搜索词的前缀长度,在此长度内不会应用模糊匹配。默认是0,即整个词都会被模糊匹配。

示例

GET /employee/_search{ \"query\": { \"fuzzy\": { \"address\": { \"value\": \"大楼\", \"fuzziness\": 1 } } }}

3.10 term set——用于解决多值字段中的文档匹配问题

terms_set 查询是 Elasticsearch 针对多值字段(通常为 keyword 类型)设计的一种特殊查询,专门用于处理基于特定术语集合的匹配计数需求。它有效解决了传统查询在多值场景下难以处理的复杂匹配问题。

传统查询存在以下局限性:

  1. terms 查询:执行逻辑 OR 运算。例如 {\"terms\": {\"tags\": [\"search\", \"database\"]}} 会匹配包含 \"search\" 或 \"database\" 中任意一个术语的文档。

  2. bool + must (AND) 查询:执行逻辑 AND 运算。例如 {\"bool\": {\"must\": [{\"term\": {\"tags\": \"search\"}}, {\"term\": {\"tags\": \"database\"}}]}} 会匹配同时包含 \"search\" 和 \"database\" 的文档。

但当需要实现更灵活的匹配条件时,传统查询就显得力不从心,例如:

  • 匹配包含 [\'elasticsearch\', \'search\', \'database\', \'nosql\'] 中至少 2 个术语的文档
  • 查找拥有 [\'read\', \'write\', \'delete\'] 全部权限的用户(即 K=集合大小)
  • 筛选出具有 [\'red\', \'blue\', \'green\'] 中恰好 1 个颜色属性的商品

使用纯 bool 查询实现\"至少 K 个\"的匹配条件会导致查询变得极其复杂且低效(需要组合所有可能的 C(n,k) 情况)。terms_set 查询正是为优雅解决这类问题而设计的解决方案。

基本语法

terms_set可以检索至少匹配一定数量给定词项的文档,其中匹配的数量可以是固定值,也可以是基于另一个字段的动态值

基本语法如下

GET //_search{ \"query\": { \"terms_set\": { \"\": { \"terms\": [\"\", \"\", ...], \"minimum_should_match_field\": \"\" or \"minimum_should_match_script\": { \"source\": \"\" } } } }}
  • : 指定要查询的字段名,这个字段通常是一个多值字段。
  • terms: 提供一组词项,用于在指定字段中进行匹配。
  • minimum_should_match_field: 指定一个包含匹配数量的字段名,其值应用作要匹配的最少术语数,以便返回文档。
  • minimum_should_match_script: 提供一个自定义脚本,用于动态计算匹配数量。如果需要动态设置匹配所需的术语数,这个参数将非常有用。

示例

假设我们有一个电影数据库,其中每部电影都有多个标签。现在,我们希望找到同时具有一定数量的给定标签的电影。

测试数据

PUT /movies{ \"mappings\": { \"properties\": { \"title\": { \"type\": \"text\" }, \"tags\": { \"type\": \"keyword\" }, \"tags_count\": { \"type\": \"integer\" } } }}POST /movies/_bulk{\"index\":{\"_id\":1}}{\"title\":\"电影1\", \"tags\":[\"喜剧\",\"动作\",\"科幻\"], \"tags_count\":3}{\"index\":{\"_id\":2}}{\"title\":\"电影2\", \"tags\":[\"喜剧\",\"爱情\",\"家庭\"], \"tags_count\":3}{\"index\":{\"_id\":3}}{\"title\":\"电影3\", \"tags\":[\"动作\",\"科幻\",\"家庭\"], \"tags_count\":3}
  • 使用固定数量的term进行匹配
GET /movies/_search{ \"query\": { \"terms_set\": { \"tags\": { \"terms\": [ \"喜剧\", \"动作\", \"科幻\" ], \"minimum_should_match\": 2 } } }}GET /movies/_search{ \"query\": { \"terms_set\": { \"tags\": { \"terms\": [ \"喜剧\", \"动作\", \"科幻\" ], \"minimum_should_match_script\": { \"source\": \"2\" } } } }}
  • 使用动态计算的term数量进行匹配
GET /movies/_search{ \"query\": { \"terms_set\": { \"tags\": { \"terms\": [ \"喜剧\", \"动作\", \"科幻\" ], \"minimum_should_match_field\": \"tags_count\" } } }}GET /movies/_search{ \"query\": { \"terms_set\": { \"tags\": { \"terms\": [ \"喜剧\", \"动作\", \"科幻\" ], \"minimum_should_match_script\": { \"source\": \"doc[\'tags_count\'].value*0.7\" } } } }}

4. 全文检索

全文检索查询旨在基于相关性搜索和匹配文本数据。这些查询会对输入的文本进行分析,将其拆分为词项(单个单词),并执行诸如分词、词干处理和标准化等操作。此类检索主要应用于非结构化文本数据,如文章和评论等。

4.1 match——分词查询

match查询是一种全文搜索查询,它使用分析器将查询字符串分解成单独的词条,并在倒排索引中搜索这些词条。match查询适用于文本字段,并且可以通过多种参数来调整搜索行为。

对于match查询,其底层逻辑的概述:

1.分词:首先,输入的查询文本会被分词器进行分词。分词器会将文本拆分成一个个词项(terms),如单词、短语或特定字符。分词器通常根据特定的语言规则和配置进行操作。

2.匹配计算:一旦查询被分词,ES将根据查询的类型和参数计算文档与查询的匹配度。对于match查询,ES将比较查询的词项与倒排索引中的词项,并计算文档的相关性得分。相关性得分衡量了文档与查询的匹配程度。

3.结果返回:根据相关性得分,ES将返回最匹配的文档作为搜索结果。搜索结果通常按照相关性得分进行排序,以便最相关的文档排在前面。

基本语法

一个基本的match查询的结构如下:

GET //_search{ \"query\": { \"match\": { \"\": \"\" } }}
  •  是你要搜索的索引名称。
  •  是你要在其中搜索的字段名称。
  •  是你要搜索的文本字符串。

示例

#分词后or的效果GET /employee/_search{ \"query\": { \"match\": { \"address\": \"番禺万民城\" } }}# 分词后 and的效果GET /employee/_search{ \"query\": { \"match\": { \"address\": { \"query\": \"番禺万民城\", \"operator\": \"and\" } } }}

在match中的应用: 当operator参数设置为or时,minnum_should_match参数用来控制匹配的分词的最少数量。

# 最少匹配广州,塔两个词GET /employee/_search{ \"query\": { \"match\": { \"address\": { \"query\": \"广州塔\", \"minimum_should_match\": 2 } } }}

4.2 multi_match——多字段查询

multi_match查询在Elasticsearch中用于在多个字段上执行相同的搜索操作。它可以接受一个查询字符串,并在指定的字段集合中搜索这个字符串。multi_match查询提供了灵活的匹配类型和操作符选项,以便根据不同的搜索需求调整搜索行为。

基本语法

一个基本的multi_match查询的结构如下:

GET //_search{ \"query\": { \"multi_match\": { \"query\": \"\", \"fields\": [\"\", \"\", ...] } }}
  •  是你要搜索的索引名称。
  •  是你要在多个字段中搜索的字符串。
  •  , , ... 是你要搜索的字段列表。

示例

GET /employee/_search{ \"query\": { \"multi_match\": { \"query\": \"江门java\", \"fields\": [ \"address\", \"remark\" ] } }}

4.3 match_phrase短语查询

match_phrase查询在Elasticsearch中用于执行短语搜索,它不仅匹配整个短语,而且还考虑了短语中各个词的顺序和位置。这种查询类型对于搜索精确短语非常有用,尤其是在用户输入的查询与文档中的文本表达方式需要严格匹配时。

基本语法

一个基本的match_phrase查询的结构如下:

GET //_search{ \"query\": { \"match_phrase\": { \"\": { \"query\": \"\" } } }}
  • 是你要搜索的索引名称。
  • 是你要在其中搜索短语的字段名称。
  • 是你要搜索的短语。

match_phrase查询还支持一个可选的slop参数,用于指定短语中词之间可以出现的最大位移数量。默认值为0,意味着短语中的词必须严格按照顺序出现。如果设置了非零的slop值,则允许短语中的某些词在一定范围内错位。

GET /employee/_search{ \"query\": { \"match_phrase\": { \"address\": \"广州白云\" } }}GET /employee/_search{ \"query\": { \"match_phrase\": { \"address\": \"广州白云山\" } }}

示例

GET /employee/_search{ \"query\": { \"match_phrase\": { \"address\": \"广州白云山\" } }}GET /employee/_search{ \"query\": { \"match_phrase\": { \"address\": \"广州白云\" } }}

思考:为什么查询广州白云山有数据,广州白云没有数据?

分析原因:

先查看广州白云山公园分词结果,可以知道广州和白云不是相邻的词条,中间会隔一个白云山,而match_phrase匹配的是相邻的词条,所以查询广州白云山有结果,但查询广州白云没有结果。

POST _analyze{ \"analyzer\":\"ik_max_word\", \"text\":\"广州白云山\"}#结果{ \"tokens\" : [ { \"token\" : \"广州\", \"start_offset\" : 0, \"end_offset\" : 2, \"type\" : \"CN_WORD\", \"position\" : 0 }, { \"token\" : \"白云山\", \"start_offset\" : 2, \"end_offset\" : 5, \"type\" : \"CN_WORD\", \"position\" : 1 }, { \"token\" : \"白云\", \"start_offset\" : 2, \"end_offset\" : 4, \"type\" : \"CN_WORD\", \"position\" : 2 }, { \"token\" : \"云山\", \"start_offset\" : 3, \"end_offset\" : 5, \"type\" : \"CN_WORD\", \"position\" : 3 } ]}

如何解决词条间隔的问题?可以借助slop参数,slop参数告诉match_phrase查询词条能够相隔多远时仍然将文档视为匹配。

#广州云山分词后相隔为2,可以匹配到结果GET /employee/_search{ \"query\": { \"match_phrase\": { \"address\": { \"query\": \"广州云山\", \"slop\": 2 } } }}

4.4 match_phrase_prefix——短语前缀匹配严格顺序) 

场景:自动补全、搜索框实时提示
特点

  • 最后一个词做前缀匹配

  • 需控制 max_expansions 防性能问题

基本语法

GET //_search{ \"query\": { \"match_phrase_prefix\": { \"\": { \"query\": \"\", // 必需参数 \"max_expansions\": 50,  // 可选参数 \"slop\": 2,// 可选参数 \"analyzer\": \"\" // 可选参数 } } }}
  • 是你要搜索的索引名称。
  • 是你要在其中搜索短语的字段名称。
  • 是你要搜索的短语。
  •  指定分词器处理查询文本
  • max_expansions 限制最后一个词的前缀扩展数量

    • 示例
      \"max_expansions\": 10
      搜索 \"elast\" 时,最多考虑 10 个以 \"elast\" 开头的词(如 elastic, elasticity, elastomer...)

  • slop 允许词项之间的间隔距离

示例

GET /employee/_search{ \"query\": { \"match_phrase_prefix\": { \"address\": { \"query\": \"广\", // 匹配 \"广\" 等 \"max_expansions\": 2 // 限制扩展词数量 } } }}

4.5 match_bool_prefix——短语前缀匹配无顺序) 

match_bool_prefix查询的工作原理如下:

首先通过分词器将输入文本拆分为多个词项(tokens),然后对除最后一个词项外的所有词项执行精确匹配(term查询),仅对最后一个词项进行前缀匹配(prefix查询)。

该查询本质上构建了一个布尔查询结构,其中前面的词项都以must条件进行精确匹配,而最后一个词项则采用前缀匹配方式。

基本语法

GET //_search{ \"query\": { \"match_bool_prefix\": { \"\": { \"query\": \"\", // 必需参数 \"analyzer\": \"\", // 可选 \"minimum_should_match\": 2, // 可选 \"fuzziness\": \"AUTO\",  // 可选(仅对最后词项生效) \"boost\": 2.0  // 可选 } } }}
  • 是你要搜索的索引名称。
  • 是你要在其中搜索短语的字段名称。
  • 是你要搜索的短语。
  •  指定分词器处理查询文本
  • minimum_should_match 必须匹配的最少词项数 
    • 配置值类型

      类型 示例 说明 整数 2 必须匹配至少2个词项 百分比 75% 匹配 ≥ 总词项数×75% 的词项 组合 3<90% 词项≤3时全匹配,>3时匹配90% 动态 2<-1 总词项数-1(至少匹配N-1个)
  • fuzziness 对最后一个词项启用模糊匹配(前面词项仍精确匹配)
    • 配置值类型

      值 说明 0 关闭模糊匹配(默认) 1 允许1个字符的编辑距离 2 允许2个字符的编辑距离 AUTO 基于词长自动选择:
      - 1-2字符:0
      - 3-5字符:1
      >5字符:2
  • boost 查询权重

示例

# 匹配要求:#必须满足以下任一组合:#1. \"广州\" + \"天河*\"(完整匹配)#2. 仅当词项>2时允许75%匹配GET /employee/_search{ \"query\": { \"match_bool_prefix\": { \"address\": { \"query\": \"广州 天河\",  \"minimum_should_match\": \"2<75%\", // 动态匹配阈值(核心参数) \"fuzziness\": 1,  // 最后词项模糊匹配 \"boost\": 1.5  // 适度权重提升 } } }}

匹配结果示例

文档地址 匹配词项 是否匹配 原因 \"广州天河区体育西路\" 广州 + 天河*(天河区) ✅ 满足2个词项 \"广州市天河软件园\" 广州 + 天河*(天河) ✅ 满足2个词项 \"广州番禺区\" 广州(缺少天河*) ❌ 只匹配1个词项 <2 \"北京天河科技大厦\" 天河*(但缺少广州) ❌ 只匹配1个词项 <2 \"广州白云机场T3航站楼\" 广州(缺少天河*) ❌ 只匹配1个词项 <2

4.6 query_string——支持与或非表达式的查询

query_string查询是一种灵活的查询类型,它允许使用Lucene查询语法来构建复杂的搜索查询。这种查询类型支持多种逻辑运算符,包括与(AND)、或(OR)和非(NOT),以及通配符、模糊搜索和正则表达式等功能。query_string查询可以在单个或多个字段上进行搜索,并且可以处理复杂的查询逻辑。

应用场景包括高级搜索、数据分析和报表等,适合处理需满足特定需求、要求支持与或非表达式的复杂查询任务,通常用于专业领域或需要高级查询功能的应用中。

基本语法

query_string查询的基本语法结构如下:

GET //_search{ \"query\": { \"query_string\": { \"query\": \"\", \"default_field\": \"\" } }}
  • 是查询逻辑,可以包含上述提到的逻辑运算符和通配符等
  • 是默认搜索字段,如果省略则会搜索所有可索引字段.

示例

  • 未指定字段查询
# AND 要求大写GET /employee/_search{ \"query\": { \"query_string\": { \"query\": \"赵六 AND 南村万博\" } }}
  • 指定单个字段查询
GET /employee/_search{ \"query\": { \"query_string\": { \"default_field\": \"address\", \"query\": \"白云山 OR 南村\" } }}

注意: 查询字段分词就将查询条件分词查询,查询字段不分词将查询条件不分词查询

  • 指定多个字段查询
GET /employee/_search{ \"query\": { \"query_string\": { \"fields\": [\"name\",\"address\"], \"query\": \"张三 OR (番禺 AND 王五)\" } }}

4.7 simple_query_string——更安全的 query_string 替代品

Query String类似,但具有更强的容错性:

  • 自动忽略语法错误
  • 仅支持部分查询语法
  • 不支持完整的AND/OR/NOT逻辑(这些关键词会被视为普通字符串)

支持简化的逻辑运算符:

  • + 代替 AND
  • | 代替 OR
  • - 代替 NOT

生产环境建议:
优先使用simple_query_string而非query_string,因其:

  • 语法更宽松
  • 可容忍输入错误
  • 避免因语法问题导致查询失败

基础语法结构示例:

GET //_search{ \"query\": { \"simple_query_string\": { \"query\": \"\", \"fields\": [\"\", \"\", ...], \"default_operator\": \"OR\" // 或 \"AND\" } }}
  •  是要搜索的査询表达式。
  • ,,.. 是搜索可以在其中进行的字段列表
  • default operator 定义了查询字符串中未指定操作符时的默认逻辑运算符,可以是\"OR\"或\"AND\"。

示例

#simple_query_string 默认的operator是ORGET /employee/_search{ \"query\": { \"simple_query_string\": { \"fields\": [\"name\",\"address\"], \"query\": \"广州白云\", \"default_operator\": \"AND\" } }}GET /employee/_search{ \"query\": { \"simple_query_string\": { \"fields\": [\"name\",\"address\"], \"query\": \"广州 + 白云\" } }}

总结: 精确匹配与全文检索的本质区别主要表现在两个方面:

  • 精确不对待检索文本进行分词处理,而是将整个文本视为一个完整的词条进行匹配。
  • 全文检索则需要对文本进行分词处理。在分词后,每个词条将单独进行检索,并通过布尔逻辑(如与、或、非等)进行组合检索,以找到最相关的结果。

4.8 interval—— 高级文本匹配工具

interval 查询是 Elasticsearch 提供的一种高级文本匹配工具,它允许您通过定义精确的规则来控制查询词项在文档中的出现顺序、间隔和关系。这种查询特别适用于需要精细控制匹配模式的场景,如法律文本、专利搜索、歌词匹配等。

基本语法结构

GET /your_index/_search{ \"query\": { \"intervals\": { \"\": { \"\": { // 规则特定参数 \"intervals\": [ // 子规则数组 { ... }, { ... } ], // 通用参数 \"ordered\": true|false, \"max_gaps\": 整数, \"filter\": { ... } } } } }}

核心概念解释

1. 规则类型 (Rule Types)

规则类型

描述

使用场景

all_of

必须匹配所有子规则

严格的多条件匹配

any_of

匹配任意子规则

同义词或可选条件

match

匹配单个词项/短语

基础词项匹配

prefix

匹配前缀

自动补全场景

wildcard

通配符匹配

模糊匹配

fuzzy

模糊匹配

容错拼写错误

2. 通用参数

参数

类型

默认值

描述

ordered

boolean

false

是否要求子规则按顺序匹配

max_gaps

integer

-1 (无限制)

允许的最大间隔词数

filter

object

-

对匹配结果应用额外过滤

详细语法解释

基础匹配规则 (match)

{ \"match\": { \"query\": \"搜索词\", \"analyzer\": \"分词器\", \"use_field\": \"字段名\" }}

组合规则 (all_of/any_of)

{ \"all_of\": { \"ordered\": true, \"max_gaps\": 2, \"intervals\": [ { \"match\": { \"query\": \"词1\" } }, { \"match\": { \"query\": \"词2\" } } ] }}

实用示例解析

示例 1:精确法律条款匹配

匹配\"版权\"后跟\"侵权\"或\"违反\",最后是\"处罚\",最多允许5个词间隔

GET /legal_docs/_search{ \"query\": { \"intervals\": { \"content\": { \"all_of\": { \"ordered\": true, \"max_gaps\": 5, \"intervals\": [ { \"match\": { \"query\": \"版权\" } }, {  \"any_of\": { \"intervals\": [  { \"match\": { \"query\": \"侵权\" } },  { \"match\": { \"query\": \"违反\" } } ]  } }, { \"match\": { \"query\": \"处罚\" } } ] } } } }}

示例 2:歌词匹配(允许词序变化)

匹配\"月亮\"和\"代表\",顺序不限,中间最多3个词

GET /song_lyrics/_search{ \"query\": { \"intervals\": { \"lyrics\": { \"all_of\": { \"ordered\": false, // 不要求顺序 \"max_gaps\": 3, \"intervals\": [ { \"match\": { \"query\": \"月亮\" } }, { \"match\": { \"query\": \"代表\" } } ] } } } }}

示例 3:专利搜索(带同义词和模糊匹配)

匹配\"人工智能\"后跟\"医疗\"或\"健康\",然后是\"诊断\"的模糊匹配

GET /patents/_search{ \"query\": { \"intervals\": { \"abstract\": { \"all_of\": { \"ordered\": true, \"intervals\": [ { \"match\": { \"query\": \"人工智能\" } }, {  \"any_of\": { \"intervals\": [  { \"match\": { \"query\": \"医疗\" } },  { \"match\": { \"query\": \"健康\" } } ]  } }, {  \"fuzzy\": { \"term\": \"诊断\", \"fuzziness\": 1, // 允许1个字符差异 \"prefix_length\": 1 // 要求首字符相同  } } ] } } } }}

示例 4:排除特定内容的匹配

匹配\"云服务\"后跟\"安全\",但不包含\"漏洞\"的内容

GET /tech_articles/_search{ \"query\": { \"intervals\": { \"content\": { \"all_of\": { \"ordered\": true, \"intervals\": [ { \"match\": { \"query\": \"云服务\" } }, { \"match\": { \"query\": \"安全\" } } ], \"filter\": { \"not_containing\": {  \"match\": { \"query\": \"漏洞\"  } } } } } } }}

5. bool query布尔查询

布尔查询允许通过布尔逻辑条件组合多个查询语句,仅返回符合整体条件的文档。布尔条件可包含两种不同上下文:

  1. 搜索上下文(query context)
    在此上下文中,Elasticsearch会计算文档与查询条件的相关度得分。该计算涉及复杂公式,会产生一定性能开销。适合需要文本分析的全文检索查询。

  2. 过滤上下文(filter context)
    在此上下文中,Elasticsearch仅判断文档是否匹配查询条件(如Term query验证值是否一致,Range query检查数值区间等)。过滤查询无需计算相关度得分,且可利用缓存提升查询速度,适合大多数术语级查询。

布尔查询支持四种组合类型:

类型

说明

must

可包含多个查询条件,每个条件均满足的文档才能被搜索到,每次查询需要计算相关度得分,属于搜索上下文 

should

可包含多个查询条件,不存在must和fiter条件时,至少要满足多个查询条件中的一个,文档才能被搜索到,否则需满足的条件数量不受限制,匹配到的查询越多相关度越高,也属于搜索上下文 

filter

可包含多个过滤条件,每个条件均满足的文档才能被搜索到,每个过滤条件不计算相关度得分,结果在一定条件下会被缓存, 属于过滤上下文 

must_not

可包含多个过滤条件,每个条件均不满足的文档才能被搜索到,每个过滤条件不计算相关度得分,结果在一定条件下会被缓存, 属于过滤上下文 

示例

PUT /books{ \"settings\": { \"number_of_replicas\": 1, \"number_of_shards\": 1 }, \"mappings\": { \"properties\": { \"id\": { \"type\": \"long\" }, \"title\": { \"type\": \"text\", \"analyzer\": \"ik_max_word\" }, \"language\": { \"type\": \"keyword\" }, \"author\": { \"type\": \"keyword\" }, \"price\": { \"type\": \"double\" }, \"publish_time\": { \"type\": \"date\", \"format\": \"yyyy-MM-dd\" }, \"description\": { \"type\": \"text\", \"analyzer\": \"ik_max_word\" } } }}POST /_bulk{\"index\":{\"_index\":\"books\",\"_id\":\"1\"}}{\"id\":\"1\", \"title\":\"Java编程思想\", \"language\":\"java\", \"author\":\"Bruce Eckel\", \"price\":70.20, \"publish_time\":\"2007-10-01\", \"description\":\"Java学习必读经典,殿堂级著作!赢得了全球程序员的广泛赞誉。\"}{\"index\":{\"_index\":\"books\",\"_id\":\"2\"}}{\"id\":\"2\",\"title\":\"Java程序性能优化\",\"language\":\"java\",\"author\":\"葛一鸣\",\"price\":46.5,\"publish_time\":\"2012-08-01\",\"description\":\"让你的Java程序更快、更稳定。深入剖析软件设计层面、代码层面、JVM虚拟机层面的优化方法\"}{\"index\":{\"_index\":\"books\",\"_id\":\"3\"}}{\"id\":\"3\",\"title\":\"Python科学计算\",\"language\":\"python\",\"author\":\"张若愚\",\"price\":81.4,\"publish_time\":\"2016-05-01\",\"description\":\"零基础学python,光盘中作者独家整合开发winPython运行环境,涵盖了Python各个扩展库\"}{\"index\":{\"_index\":\"books\",\"_id\":\"4\"}}{\"id\":\"4\", \"title\":\"Python基础教程\", \"language\":\"python\", \"author\":\"Helant\", \"price\":54.50, \"publish_time\":\"2014-03-01\", \"description\":\"经典的Python入门教程,层次鲜明,结构严谨,内容翔实\"}{\"index\":{\"_index\":\"books\",\"_id\":\"5\"}}{\"id\":\"5\",\"title\":\"JavaScript高级程序设计\",\"language\":\"javascript\",\"author\":\"Nicholas C. Zakas\",\"price\":66.4,\"publish_time\":\"2012-10-01\",\"description\":\"JavaScript技术经典名著\"}GET /books/_search{ \"query\": { \"bool\": { \"must\": [ { \"match\": { \"title\": \"java编程\" } },{ \"match\": { \"description\": \"性能优化\" } } ] } }}GET /books/_search{ \"query\": { \"bool\": { \"should\": [ { \"match\": { \"title\": \"java编程\" } },{ \"match\": { \"description\": \"性能优化\" } } ], \"minimum_should_match\": 1 } }}GET /books/_search{ \"query\": { \"bool\": { \"filter\": [ { \"term\": { \"language\": \"java\" } }, { \"range\": { \"publish_time\": {  \"gte\": \"2010-08-01\" } } } ] } }}

6. highlight高亮

highlight 关键字: 可以让符合条件的文档中的关键词高亮。 highlight相关属性:

  • pre_tags 前缀标签
  • post_tags 后缀标签
  • tags_schema 设置为styled可以使用内置高亮样式
  • require_field_match 多字段高亮需要设置为false

示例

#指定ik分词器PUT /products{ \"settings\" : { \"index\" : { \"analysis.analyzer.default.type\": \"ik_max_word\" } }}PUT /products/_doc/1{ \"proId\" : \"2\", \"name\" : \"牛仔男外套\", \"desc\" : \"牛仔外套男装春季衣服男春装夹克修身休闲男生潮牌工装潮流头号青年春秋棒球服男 7705浅蓝常规 XL\", \"timestamp\" : 1576313264451, \"createTime\" : \"2019-12-13 12:56:56\"}PUT /products/_doc/2{ \"proId\" : \"6\", \"name\" : \"HLA海澜之家牛仔裤男\", \"desc\" : \"HLA海澜之家牛仔裤男2019时尚有型舒适HKNAD3E109A 牛仔蓝(A9)175/82A(32)\", \"timestamp\" : 1576314265571, \"createTime\" : \"2019-12-18 15:56:56\"}GET /products/_search{ \"query\": { \"term\": { \"name\": { \"value\": \"牛仔\" } } }, \"highlight\": { \"fields\": { \"*\":{} } }}

自定义高亮html标签

可以在highlight中使用pre_tags和post_tags

GET /products/_search{ \"query\": { \"multi_match\": { \"fields\": [\"name\",\"desc\"], \"query\": \"牛仔\" } }, \"highlight\": { \"post_tags\": [\"\"], \"pre_tags\": [\"\"], \"fields\": { \"*\":{} } }}

多字段高亮

GET /products/_search{ \"query\": { \"term\": { \"name\": { \"value\": \"牛仔\" } } }, \"highlight\": { \"pre_tags\": [\"\"], \"post_tags\": [\"\"], \"require_field_match\": \"false\", \"fields\": { \"name\": {}, \"desc\": {} } }}
  • require_field_match: 该设置控制是否需要所有指定的高亮字段都匹配搜索查询,才能应用高亮。当设置为false时,只要任意一个字段匹配,该文档的匹配部分就会被高亮。如果设置为true,则所有指定的字段都必须匹配查询条件。

    7. 地理空间位置查询

    地理空间位置查询是数据库和搜索系统中的一个重要特性,特别是在地理信息系统(GIS)和位置服务中。它允许用户基于地理位置信息来搜索和过滤数据。在Elasticsearch这样的全文搜索引擎中,地理空间位置查询被广泛应用,例如在旅行、房地产、物流和零售等行业,用于提供基于位置的搜索功能。

    在Elasticsearch中,地理空间数据通常存储在geo_point字段类型中。这种字段类型可以存储纬度和经度坐标,用于表示地球上的一个点。

    以下是一个使用geo_distance查询的例子,它会找到距离特定点一定距离内的所有文档。

    1)确保索引中有一个geo_point字段,例如location。

    PUT /my_index{ \"mappings\": { \"properties\": { \"location\": { \"type\": \"geo_point\" } } }}

    2)使用以下查询来找到距离给定坐标点(例如lat和lon)小于或等于10公里的所有文档:

    GET /my_index/_search{ \"query\": { \"bool\": { \"must\": { \"match_all\": {} }, \"filter\": { \"geo_distance\": { \"distance\": \"10km\", \"distance_type\": \"arc\", \"location\": { \"lat\": 39.9, \"lon\": 116.4 } } } } }}

    在这个查询中:

    • \"bool\" 是一个逻辑查询容器,用于组合多个查询子句。
    • \"match_all\" 是一个匹配所有文档的查询子句。
    • \"geo_distance\" 是一个地理距离查询,它允许您指定一个距离和一个点的坐标。
    • \"distance\" 是查询的最大距离,单位可以是米(m)、公里(km)等。
    • \"distance_type\" 可以是 arc(以地球表面的弧长为单位)或 plane(以直线距离为单位)。通常对于地球上的距离查询,建议使用 arc。
    • \"location\" 是查询的参考点,包含纬度和经度坐标。

    这个查询将返回索引my_index中location字段在给定坐标点10公里范围内的所有文档。 示例

    假设我们正在管理一个记录中国各地著名景点的索引,每个景点都带有地理坐标。以下是一些示例数据:

    # 创建索引PUT /tourist_spots{ \"mappings\": { \"properties\": { \"name\": { \"type\": \"text\", \"analyzer\": \"ik_max_word\", \"search_analyzer\": \"ik_max_word\" }, \"location\": { \"type\": \"geo_point\" } } }}# 插入文档POST /tourist_spots/_doc{ \"name\": \"故宫博物院\", \"location\": { \"lat\": 39.9159, \"lon\": 116.3945 }, \"city\": \"北京\"}POST /tourist_spots/_doc{ \"name\": \"西湖\", \"location\": { \"lat\": 30.2614, \"lon\": 120.1479 }, \"city\": \"杭州\"}POST /tourist_spots/_doc{ \"name\": \"雷峰塔\", \"location\": { \"lat\": 30.2511, \"lon\": 120.1347 }, \"city\": \"杭州\"}POST /tourist_spots/_doc{ \"name\": \"苏堤春晓\", \"location\": { \"lat\": 30.2584, \"lon\": 120.1383 }, \"city\": \"杭州\"}# 搜索包含故宫或博物院的景点:GET /tourist_spots/_search{ \"query\": { \"match\": { \"name\": \"故宫 博物院\" } }}# 查询北京附近的景点GET /tourist_spots/_search{ \"query\": { \"bool\": { \"must\": { \"match_all\": {} }, \"filter\": { \"geo_distance\": { \"distance\": \"10km\", \"distance_type\": \"arc\", \"location\": { \"lat\": 39.9159, \"lon\": 116.3945 } } } } }}# 查询杭州西湖5km附近的景点#雷峰塔 - 位于西湖附近,距离约2.8公里。#苏堤春晓 - 位于西湖边,距离西湖中心约1公里。GET /tourist_spots/_search{ \"query\": { \"bool\": { \"must\": { \"match_all\": {} }, \"filter\": { \"geo_distance\": { \"distance\": \"5km\", \"distance_type\": \"arc\", \"location\": { \"lat\": 30.2614, \"lon\": 120.1479 } } } } }}

    8. ElasticSearch8.x 向量检索

    Elasticsearch 8.x 引入了一个重要的新特性:向量检索(Vector Search),特别是通过KNN(K-Nearest Neighbors)算法支持向量近邻检索。这一特性使得Elasticsearch在机器学习、数据分析和推荐系统等地方的应用变得更加广泛和强大。

    向量检索的基本思路是,将文档(或数据项)表示为高维向量,并使用这些向量来执行相似性搜索。在Elasticsearch中,这些向量被存储在dense_vector类型的字段中,然后使用KNN算法来找到与给定向量最相似的其他向量。

    PUT image-index{ \"mappings\": { \"properties\": { \"image-vector\": { \"type\": \"dense_vector\", \"dims\": 3 }, \"title\": { \"type\": \"text\" }, \"file-type\": { \"type\": \"keyword\" }, \"my_label\": { \"type\": \"text\" } } }}POST image-index/_bulk{ \"index\": {} }{ \"image-vector\": [-5, 9, -12], \"title\": \"Image A\", \"file-type\": \"jpeg\", \"my_label\": \"red\" }{ \"index\": {} }{ \"image-vector\": [10, -2, 3], \"title\": \"Image B\", \"file-type\": \"png\", \"my_label\": \"blue\" }{ \"index\": {} }{ \"image-vector\": [4, 0, -1], \"title\": \"Image C\", \"file-type\": \"gif\", \"my_label\": \"red\" }POST image-index/_search{ \"knn\": { \"field\": \"image-vector\", \"query_vector\": [-5, 10, -12], \"k\": 10, \"num_candidates\": 100 }, \"fields\": [ \"title\", \"file-type\" ]}