接着上一篇,继续梳理 ES 检索文档的两种方式,即结构化检索和全文检索。
结构化检索,建议参考官方文档:Term-level queries | Elasticsearch Guide [6.8] | Elastic
全文检索,也建议参考官方文档:Full text queries | Elasticsearch Guide [6.8] | Elastic
term query 表示单个精准值查询,而 terms query 表示多个精准值查询。请注意,字段的数据类型是 text 或 keyword 类型。
- GET mytest_index_0626/_search?pretty&track_total_hits=true
- {
- "query": {
- "term": {
- "pkey": "15556905959_10011" //单个精准值查询
- }
- }
- }
-
- GET mytest_index_0626/_search?pretty&track_total_hits=true
- {
- "query": {
- "terms": {
- "pkey": ["15556905959_10011","15556905756_10010"] //多个精准值查询
- }
- }
- }
bool query 查询选项有:must、must_not、should、filter,它们的区别如下:
- GET mytest_index_0626/_search?pretty&track_total_hits=true
- {
- "query": {
- "bool": {
- "must": [
- {"term": {"status": "U"}},
- {"term": {"myObj.sign_no": "10010"}}
- ]
- }
- }
- }
- # 索引的文档,①不存在,使用must_not查询,会输出所有包含flag=0的文档
- GET mytest_index_0626/_search?pretty&track_total_hits=true
- {
- "query": {
- "bool": {
- "must_not": [
- {"term": {"flag": 1}} //①
- ]
- }
- }
- }
- # 索引的文档,①不存在,②存在一条,使用should查询会输出一条结果
- GET mytest_index_0626/_search?pretty&track_total_hits=true
- {
- "query": {
- "bool": {
- "should": [
- {"term": {"flag": 1}}, //①
- {"term": {"myObj.user_id": "15556905756"}} //②
- ]
- }
- }
- }
- # 索引的文档,①不存在,②存在一条,使用filter查询不到结果
- GET mytest_index_0626/_search?pretty&track_total_hits=true
- {
- "query": {
- "bool": {
- "filter": [
- {"term": {"flag": 1}}, //①
- {"term": {"myObj.user_id": "15556905756"}} //②
- ]
- }
- }
- }
- GET mytest_index_0626/_search?pretty&track_total_hits=true
- {
- "query": {
- "prefix": {
- "myObj.user_id": "155" //匹配 myObj.user_id 前缀包含155字符串的文档
- }
- }
- }
查找在模糊度中指定的最大编辑距离内的所有可能匹配项,再检查术语字典,以找出在索引中实际存在待检索的关键词:
- # 索引中存在一条pkey=15556905954_10010的文档
- GET mytest_index_0626/_search?pretty&track_total_hits=true
- {
- "query": {
- "fuzzy": {
- //"pkey": "15556905954" //匹配找不到对应结果
- //"pkey": "15556905954_10" //仍然匹配找不到对应结果
- "pkey": "15556905954_1001"
- }
- }
- }
适合数值类型的字段进行范围查询,范围比较的关键字有:
- # 查询 myObj.pay_amount 的支付金额值,范围为[20,50)
- GET mytest_index_0626/_search?pretty&track_total_hits=true
- {
- "query": {
- "range": {
- "myObj.pay_amount": {
- "gte": "20",
- "lt": "50"
- }
- }
- }
- }
-
- # 多个字段值得范围查询
- GET mytest_index_0626/_search?pretty&track_total_hits=true
- {
- "query": {
- "bool": {
- "filter": [
- {
- "range": {
- "myObj.pay_amount": {
- "gte": "20",
- "lt": "50"
- }
- }
- },
- {
- "range": {
- "myObj.pay_amount1": {
- "gte": "30",
- "lte": "45"
- }
- }
- }
- ]
- }
- }
- }
通配符有:* 表示匹配任何字符序列(包括空字符序列),?表示匹配任何单个字符。
- GET mytest_index_0626/_search?pretty&track_total_hits=true
- {
- "query": {
- "wildcard": {
- "myObj.user_id": "155*"
- }
- }
- }
在 8.x 版本中已不再支持 type query 。
- # 返回指定type的文档信息
- GET mytest_index_0626/_search?pretty&track_total_hits=true
- {
- "query": {
- "type": {
- "value":"_doc"
- }
- }
- }
查询某个或多个字段是否存在:
- GET mytest_index_0626/_search?pretty&track_total_hits=true
- {
- "query": {
- "exists": {
- "field": "collection_url"
- }
- }
- }
-
- GET mytest_index_0626/_search?pretty&track_total_hits=true
- {
- "query": {
- "bool": {
- "filter": [
- {"exists": {"field": "status"}},
- {"exists": {"field": "collection_url"}}
- ]
- }
- }
- }
请注意,如果查询字段不存在,可以使用前面的 must_not 实现;
另外,如果要求 exists 查询能匹配到 null 类型,需要设置mapping,以 status 字段为例:
- "status": {
- "type": "keyword",
- "null_value": "_null_"
- }
使用.*?+通配符查询的正则检索,性能是会非常低的。
- # 返回指定id的文档信息
- GET mytest_index_0626/_search?pretty&track_total_hits=true
- {
- "query": {
- "regexp": {
- "collection_url":"https.*/hangzhou/"
- }
- }
- }
- # 返回指定id的文档信息
- GET mytest_index_0626/_search?pretty&track_total_hits=true
- {
- "query": {
- "ids": {
- "type": "_doc",
- "values":["axEwmoEBTXtCd1dvuDqv","gxHImYEBTXtCd1dv3Dfj"]
- }
- }
- }
我们知道 keyword 类型不支持分词,该类型的字段使用全文检索时,必须使用全部字符串匹配才能被查找到;而 text 类型的字段适合于全文检索,支持分词,同时要考虑具体分词器,因为不同的分词器对相同的文本字符长的分解词项可能不一样。
下面使用 wheater_infos_2022 索引演示,在该索引里新增了6.1号~6.3号、四座城市的共12条天气记录数据~
match 匹配查询,查询时会分词处理,接受文本/数字/日期等数据类型。
- # today_weather.temperature_range,该字段是text类型
- # temperature_range 原文本字符串为"26-344℃",此处会使用到默认的standard分词方式
- # 匹配 today_weather.temperature_range 包含 26 或 44
- GET wheater_infos_2022/_search?pretty&track_total_hits=true
- {
- "query": {
- "match": {
- "today_weather.temperature_range": "26 44"
- }
- }
- }
-
- # 上面的写法看不明白?上面的写法等同于下面的这种写法:
- GET wheater_infos_2022/_search?pretty&track_total_hits=true
- {
- "query": {
- "match": {
- "today_weather.temperature_range": {
- "query": "26 44",
- "operator": "or" //默认or操作
- }
- }
- }
- }
如果需要了解更多的参数设置(比如 fuzziness/zero_terms_query/cutoff_frequency 等),可参考官网文档:Match Query | Elasticsearch Guide [6.8] | Elastic
match_phrase 查询分析文本,并从分析文本中创建分词(该查询方式,首先将查询的文本字符串解析成一个词项列表,然后对这些词项进行搜索,但只保留那些包含全部搜索词项,且位置与搜索词项相同的文档)。
请注意,这句话的理解,只保留那些包含全部搜索词项,位置与搜索词项相同的文档,也就是说,我把 today_weather.temperature_range 的 "26 344",修改成 "344 26",返回查询的结果则会为空。
- GET wheater_infos_2022/_search?pretty&track_total_hits=true
- {
- "query": {
- "match_phrase": {
- "today_weather.temperature_range": "26 344"
- }
- }
- }
如果需要了解更多的参数设置(比如 analyzer),可参考官网文档:Match Phrase Query | Elasticsearch Guide [6.8] | Elastic
match_phrase_prefix 与 match_phrase 原理相同,不同的是 match_phrase_prefix 允许文本中最后一个术语可以前缀匹配。
- GET wheater_infos_2022/_search?pretty&track_total_hits=true
- {
- "query": {
- "match_phrase_prefix": {
- "today_weather.temperature_range": "34*"
- }
- }
- }
如果需要了解更多的参数设置(比如 max_expansions),可参考官网文档:Match Phrase Prefix Query | Elasticsearch Guide [6.8] | Elastic
multi_math 能在多个字段上反复执行相同的查询。默认情况下,查询的类型是 best_fields(它会为每个字段生成一个 match 查询),也支持 most_fields、cross_fields、phrase、phrase_prefix 等查询类型。
- GET wheater_infos_2021/_search?pretty&track_total_hits=true
- {
- "query": {
- "multi_match": {
- "query": "26 AND 344", //查询字符串,支持指定AND | OR | NOT条件
- "fields": [
- "today_weather.temperature",
- "today_weather.temperature_*",
- "today_weather.pm_value^2" //^2表示提示查询该字段的权重
- ]
- }
- }
- }
如果需要了解更多的参数设置(比如 type/tie_breaker 等),可参考官网文档:Multi Match Query | Elasticsearch Guide [6.8] | Elastic
query_string 许在单个查询字符串中指定AND | OR | NOT条件,同时也和 multi_match query 一样,支持多字段搜索。
请注意,query_string 不支持 keyword 类型字段查询,返回的查询结果则为空,query_string 适用于查询 text 类型的字段,且查询的分词和顺序无关,分词也不需要连续,比如 "query" 使用 "26 AND 344" 和 "344 AND 26" 查询效果是一样的!
- GET wheater_infos_2021/_search?pretty&track_total_hits=true
- {
- "query": {
- "query_string": {
- "query": "26 AND 344", //查询字符串,支持指定AND | OR | NOT条件
- "fields": [
- "today_weather.temperature"
- ]
- }
- }
- }
-
-
- GET wheater_infos_2021/_search?pretty&track_total_hits=true
- {
- "query": {
- "query_string": {
- "query": "26 AND 344", //查询字符串,支持指定AND | OR | NOT条件
- "fields": [
- "today_weather.temperature",
- "today_weather.temperature_*",
- "today_weather.pm_value^2" //^2表示提示查询该字段的权重
- ]
- }
- }
- }
如果需要了解更多的参数设置,可参考官网文档:Query String Query | Elasticsearch Guide [6.8] | Elastic
与 query_string 相比,simple_query_string 不会抛出异常,并丢弃查询的无效部分,不支持使用 AND、OR、NOT 作为连接符,而是支持下面这些方式:
(
and )
表示优先级;- GET wheater_infos_2021/_search?pretty&track_total_hits=true
- {
- "query": {
- "simple_query_string": {
- "query": "26 + 34", //查询字符串,+相当于query_string的AND
- "fields": [
- "today_weather.temperature",
- "today_weather.temperature_*",
- "today_weather.pm_value^2" //^2表示提示查询该字段的权重
- ]
- }
- }
- }
如果需要了解更多的参数设置,可参考官网文档:Simple Query String Query | Elasticsearch Guide [6.8] | Elastic
随着 ES 版本不断的更新,term-level queries 和 full-text queries 也在调整文档查询方式。比如,与 6.8 版本相比,在最新版本的 8.x 中,term-level queries 不再支持 type query,新增支持 terms_set query;又比如,full-text queries 与 6.8 版本相比新增了 intervals query、match_bool_prefix query、combined_fields query 等类型的查询。因此,平时要注意,根据自己当前使用的 ES 版本,并结合官方文档加以学习和使用。