1. ES高级查询Query DSL
ES中提供了一种强大的检索数据方式,这种检索方式称之为Query DSL(Domain Specified Language领域专用语言) , Query DSL是利用Rest API传递JSON格式的请求体(RequestBody)数据与ES进行交互,这种方式的丰富查询语法让ES检索变得更强大,更简洁。
官方文档:https://www.elastic.co/guide/en/elasticsearch/reference/8.14/query-dsl.html
基本语法:
GET //_search {json请求体数据} 示例数据准备
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"}
1.1 match_all ——匹配所有文档
match_all查询是一个特殊的查询类型,它用于匹配索引中的所有文档,而不考虑任何特定的查询条件。
基本语法
GET //_search {"query": {"match_all": {}}}
高级用法
例如,如果您想要返回索引中的前10个文档,并且按照文档的评分进行排序,您可以使用以下查询:
GET //_search {"query": {"match_all": {}},"size": 10,"sort": [{"_score": {"order": "desc"}}]}
_source的用法
#不查看源数据,仅查看元字段GET // _search{"query": {"match_all": {}},"_source": false}# 返回指定字段GET // _search{"query": {"match_all": {}},"_source": ["field1","field2"]}#只看以obj.开头的字段GET // _search{"query": {"match_all": {}},"_source": "obj.*"}
示例
size返回指定条数
GET /employee/_search{"query": {"match_all": {}},"size": 3}
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}
_source返回源数据
GET /employee/_search{"query": {"match_all": {}},"_source": ["name","address"]}
1.2 精确匹配
精确匹配是指的是搜索内容不经过文本分析直接用于文本匹配,这个过程类似于数据库的SQL查询,搜索的对象大多是索引的非text类型字段。此类检索主要应用于结构化数据,如ID、状态和标签等。
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": {"name": {"value": "张三"}}}}
注意:最好不要在term查询的字段中使用text字段,因为text字段会被分词,这样做既没有意义,还很有可能什么也查不到。
# 思考: 查询广州白云是否有数据,为什么?GET /employee/_search{"query":{"term": {"address": {"value": "广州白云"}}}}# 采用term精确查询, 查询字段映射类型为keywordGET /employee/_search{"query":{"term": {"address.keyword": {"value": "广州白云山公园"}}}}
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": "跑步"}}}}
在ES中,Term查询,对输入不做分词。会将输入作为一个整体,在倒排索引中查找准确的词项,并且使用相关度算分公式为每个包含该词项的文档进行相关度算分。
可以通过 Constant Score 将查询转换成一个 Filtering,避免算分,并利用缓存,提高性能。
将Query 转成 Filter,忽略TF-IDF计算,避免相关性算分的开销 Filter可以有效利用缓存
GET /employee/_search{"query": {"constant_score": {"filter": {"term": {"address.keyword": "广州白云山公园"}}}}}
terms——多值精确匹配
terms检索主要应用于多值精准匹配场景,它允许用户在单个查询中指定多个词条来进行精确匹配。这种查询方式适合从文档中查找包含多个特定值的字段,例如筛选出具有多个特定标签或状态的项目。而terms检索是针对未分析的字段进行精确匹配的,因此它在处理关键词、数字、日期等结构化数据时表现良好。
基本语法
在Elasticsearch 8.x中,进行多字段精确匹配时,可以使用terms查询。terms查询允许你指定一个字段,并匹配该字段中的多个精确值。
基本语法如下:
GET //_search {"query": {"terms": {"" : ["value1","value2","value3",...]}}}
方括号内的值列表是你希望在查询中匹配的字段值。
示例
POST /employee/_search{"query": {"terms": {"remark.keyword": ["java assistant", "java architect"]}}}
range——范围查询
range检索是Elasticsearch中一种针对指定字段值在给定范围内的文档的检索类型。这种查询适合对数字、日期或其他可排序数据类型的字段进行范围筛选。range检索支持多种比较操作符,如大于(gt)、大于等于(gte)、小于(lt)和小于等于(lte)等,可以实现灵活的区间查询。
基本语法
在Elasticsearch 8.x版本中,range查询的基本语法如下:
GET //_search {"query": {"range": {"" : {"gte":, "lte":, "gt":, "lt":}}}}
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}}}}
- 日期范围查询
1) 生成测试数据
假设我们正在创建一个笔记应用,每条笔记都有一个创建日期。
PUT /notes{"settings": {"number_of_shards": 1,"number_of_replicas": 0},"mappings": {"properties": {"title": {"type": "text"},"content": {"type": "text"},"created_at": {"type": "date", "format": "yyyy-MM-dd HH:mm:ss"}}}}POST /notes/_bulk{"index":{"_id":"1"}}{"title":"Note 1","content":"This is the first note.","created_at":"2023-07-01 12:00:00"}{"index":{"_id":"2"}}{"title":"Note 2","content":"This is the second note.","created_at":"2023-07-05 15:30:00"}{"index":{"_id":"3"}}{"title":"Note 3","content":"This is the third note.","created_at":"2023-07-10 08:45:00"}{"index":{"_id":"4"}}{"title":"Note 4","content":"This is the fourth note.","created_at":"2023-07-15 20:15:00"}
2)使用range查询来查找在特定日期范围内的笔记。
假设我们想找出在2023年7月5日和2023年7月10日之间的所有笔记。
POST /notes/_search{"query": {"range": {"created_at": {"gte": "2023-07-05 00:00:00","lte": "2023-07-10 23:59:59"}}}}
Elasticsearch支持日期数学表达式,允许在查询和聚合中使用相对时间点。以下是一些常见的日期数学表达式的示例和解释:
now:当前时间点。 now-1d:从当前时间点向前推1天的时间点。 now-1w:从当前时间点向前推1周的时间点。 now-1M:从当前时间点向前推1个月的时间点。 now-1y:从当前时间点向前推1年的时间点。 now+1h:从当前时间点向后推1小时的时间点。
POST /product/_bulk{"index":{"_id":1}}{"price":100,"date":"2023-01-01","productId":"XHDK-1293"}{"index":{"_id":2}}{"price":200,"date":"2022-01-01","productId":"KDKE-5421"}# 返回所有在当前时间点前两年内的产品文档。GET /product/_search{"query": {"range": {"date": {"gte": "now-2y"}}}}
exists——是否存在查询
exists检索在Elasticsearch中用于筛选具有特定字段值的文档。这种查询类型适用于检查文档中是否存在某个字段,或者该字段是否包含非空值。通过使用exists检索,你可以有效地过滤掉缺少关键信息的文档,从而专注于包含所需数据的结果。应用场景包括但不限于数据完整性检查、查询特定属性的文档以及对可选字段进行筛选等。
基本语法
GET //_search {"query": {"exists": {"field": "missing_field"}}}
示例
查询索引库中存在remark字段的文档
GET /employee/_search{"query": {"exists":{"field": "remark"}}}
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]}}}
prefix——前缀匹配
prefix会对分词后的term进行前缀搜索。
-
它不会对要搜索的字符串分词
,传入的前缀就是想要查找的前缀 默认状态下,前缀查询不做相关性分数计算,它只是将所有匹配的文档返回,然后赋予所有相关分数值为1。
prefix的原理:
需要遍历所有倒排索引,并比较每个词项是否以所搜索的前缀开头。
基本语法
在Elasticsearch 8.x中,prefix查询用于搜索那些在指定字段中以特定前缀开始的文档。这种查询通常用于自动补全或搜索功能,其中用户输入的搜索词可能是更长文本的一部分。
基本语法如下:
GET //_search {"query": {"prefix": {"your_field_name": {"value": "your_prefix_string"}}}}
需要注意的是,这种查询方式仅适用于关键字类型(keyword)的字段。
示例
# 思考:能否查到数据?GET /employee/_search{"query": {"prefix": {"address": {"value": "广州白云山"}}}}GET /employee/_search{"query": {"prefix": {"address.keyword": {"value": "广州白云山"}}}}
wildcard——通配符匹配
wildcard检索是Elasticsearch中一种支持通配符匹配的查询类型,它允许在检索时使用通配符表达式来匹配文档的字段值。通配符包括两种。
星号(*):表示零或多个字符,可用于匹配任意长度的字符串。 问号(?):表示一个字符,用于匹配任意单个字符。
wildcard检索适用于对部分已知内容的文本字段进行模糊检索。例如,在文件名或产品型号等具有一定规律的字段中,使用通配符检索可以方便地找到满足特定模式的文档。
请注意,通配符查询可能会导致较高的计算负担,因此在实际应用中应谨慎使用,尤其是在涉及大量文档的情况下。
基本语法
基本语法如下:
GET //_search {"query": {"wildcard": {"your_field_name": {"value": "your_search_pattern"}}}}
示例
GET /employee/_search{"query": {"wildcard": {"address.keyword": {"value": "*州*公园"}}}}
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.*"}}}}
.* 表示在java后可以跟随任意数量的任意字符
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}}}}
term set——用于解决多值字段中的文档匹配问题
terms set检索是Elasticsearch中一种功能强大的检索类型,主要用于解决多值字段中的文档匹配问题,在处理具有多个属性、分类或标签的复杂数据时非常有用。
从应用场景来说,terms set检索在处理多值字段和特定匹配条件时具有很大的优势。它适用于标签系统、搜索引擎、电子商务系统、文档管理系统和技能匹配等场景。
基本语法
terms_set可以检索至少匹配一定数量给定词项的文档,其中匹配的数量可以是固定值,也可以是基于另一个字段的动态值
基本语法如下:
GET //_search {"query": {"terms_set": {"" : {"terms": ["" , "" , ...],"minimum_should_match_field": "" or"minimum_should_match_script": {"source": "