• 6、Elasticsearch 检索文档的方式


    接着上一篇,继续梳理 ES 检索文档的两种方式,即结构化检索和全文检索。

    结构化检索,建议参考官方文档:Term-level queries | Elasticsearch Guide [6.8] | Elastic

    全文检索,也建议参考官方文档:Full text queries | Elasticsearch Guide [6.8] | Elastic

    一、结构化检索

    1、精准搜索之term/terms查询

    term query 表示单个精准值查询,而 terms query 表示多个精准值查询。请注意,字段的数据类型是 text 或 keyword 类型。

    1. GET mytest_index_0626/_search?pretty&track_total_hits=true
    2. {
    3. "query": {
    4. "term": {
    5. "pkey": "15556905959_10011" //单个精准值查询
    6. }
    7. }
    8. }
    9. GET mytest_index_0626/_search?pretty&track_total_hits=true
    10. {
    11. "query": {
    12. "terms": {
    13. "pkey": ["15556905959_10011","15556905756_10010"] //多个精准值查询
    14. }
    15. }
    16. }

    2、精准搜索之bool filter查询

    bool query 查询选项有:must、must_not、should、filter,它们的区别如下:

    • must:所有都必须匹配,相当于and;
    1. GET mytest_index_0626/_search?pretty&track_total_hits=true
    2. {
    3. "query": {
    4. "bool": {
    5. "must": [
    6. {"term": {"status": "U"}},
    7. {"term": {"myObj.sign_no": "10010"}}
    8. ]
    9. }
    10. }
    11. }
    • must_not:所有都必须不被匹配,相当于not;
    1. # 索引的文档,①不存在,使用must_not查询,会输出所有包含flag=0的文档
    2. GET mytest_index_0626/_search?pretty&track_total_hits=true
    3. {
    4. "query": {
    5. "bool": {
    6. "must_not": [
    7. {"term": {"flag": 1}} //①
    8. ]
    9. }
    10. }
    11. }
    • should:至少有一个匹配,相当于or;
    1. # 索引的文档,①不存在,②存在一条,使用should查询会输出一条结果
    2. GET mytest_index_0626/_search?pretty&track_total_hits=true
    3. {
    4. "query": {
    5. "bool": {
    6. "should": [
    7. {"term": {"flag": 1}}, //①
    8. {"term": {"myObj.user_id": "15556905756"}} //②
    9. ]
    10. }
    11. }
    12. }
    • filter:必须匹配,运行在非评分&过滤模式。
    1. # 索引的文档,①不存在,②存在一条,使用filter查询不到结果
    2. GET mytest_index_0626/_search?pretty&track_total_hits=true
    3. {
    4. "query": {
    5. "bool": {
    6. "filter": [
    7. {"term": {"flag": 1}}, //①
    8. {"term": {"myObj.user_id": "15556905756"}} //②
    9. ]
    10. }
    11. }
    12. }

    3、前缀搜索(prefix query)

    1. GET mytest_index_0626/_search?pretty&track_total_hits=true
    2. {
    3. "query": {
    4. "prefix": {
    5. "myObj.user_id": "155" //匹配 myObj.user_id 前缀包含155字符串的文档
    6. }
    7. }
    8. }

    4、模糊搜索(fuzzy query)

    查找在模糊度中指定的最大编辑距离内的所有可能匹配项,再检查术语字典,以找出在索引中实际存在待检索的关键词:

    1. # 索引中存在一条pkey=15556905954_10010的文档
    2. GET mytest_index_0626/_search?pretty&track_total_hits=true
    3. {
    4. "query": {
    5. "fuzzy": {
    6. //"pkey": "15556905954" //匹配找不到对应结果
    7. //"pkey": "15556905954_10" //仍然匹配找不到对应结果
    8. "pkey": "15556905954_1001"
    9. }
    10. }
    11. }

    5、范围搜索(range query)

    适合数值类型的字段进行范围查询,范围比较的关键字有:

    • gt: > 大于(greater than)
    • lt: < 小于(less than)
    • gte: >= 大于或等于(greater than or equal to)
    • lte: <= 小于或等于(less than or equal to)
    1. # 查询 myObj.pay_amount 的支付金额值,范围为[20,50)
    2. GET mytest_index_0626/_search?pretty&track_total_hits=true
    3. {
    4. "query": {
    5. "range": {
    6. "myObj.pay_amount": {
    7. "gte": "20",
    8. "lt": "50"
    9. }
    10. }
    11. }
    12. }
    13. # 多个字段值得范围查询
    14. GET mytest_index_0626/_search?pretty&track_total_hits=true
    15. {
    16. "query": {
    17. "bool": {
    18. "filter": [
    19. {
    20. "range": {
    21. "myObj.pay_amount": {
    22. "gte": "20",
    23. "lt": "50"
    24. }
    25. }
    26. },
    27. {
    28. "range": {
    29. "myObj.pay_amount1": {
    30. "gte": "30",
    31. "lte": "45"
    32. }
    33. }
    34. }
    35. ]
    36. }
    37. }
    38. }

    6、通配符搜索(wildcard query)

    通配符有:* 表示匹配任何字符序列(包括空字符序列)?表示匹配任何单个字符

    1. GET mytest_index_0626/_search?pretty&track_total_hits=true
    2. {
    3. "query": {
    4. "wildcard": {
    5. "myObj.user_id": "155*"
    6. }
    7. }
    8. }

    7、类型搜索(type query)

    在 8.x 版本中已不再支持 type query 。

    1. # 返回指定type的文档信息
    2. GET mytest_index_0626/_search?pretty&track_total_hits=true
    3. {
    4. "query": {
    5. "type": {
    6. "value":"_doc"
    7. }
    8. }
    9. }

    8、存在搜索(exists query)

    查询某个或多个字段是否存在:

    1. GET mytest_index_0626/_search?pretty&track_total_hits=true
    2. {
    3. "query": {
    4. "exists": {
    5. "field": "collection_url"
    6. }
    7. }
    8. }
    9. GET mytest_index_0626/_search?pretty&track_total_hits=true
    10. {
    11. "query": {
    12. "bool": {
    13. "filter": [
    14. {"exists": {"field": "status"}},
    15. {"exists": {"field": "collection_url"}}
    16. ]
    17. }
    18. }
    19. }

    请注意,如果查询字段不存在,可以使用前面的 must_not 实现

    另外,如果要求 exists 查询能匹配到 null 类型,需要设置mapping,以 status 字段为例:

    1. "status": {
    2. "type": "keyword",
    3. "null_value": "_null_"
    4. }

    9、正则搜索(regexp query)

    使用.*?+通配符查询的正则检索,性能是会非常低的。

    1. # 返回指定id的文档信息
    2. GET mytest_index_0626/_search?pretty&track_total_hits=true
    3. {
    4. "query": {
    5. "regexp": {
    6. "collection_url":"https.*/hangzhou/"
    7. }
    8. }
    9. }

    10、id 搜索(ids query)

    1. # 返回指定id的文档信息
    2. GET mytest_index_0626/_search?pretty&track_total_hits=true
    3. {
    4. "query": {
    5. "ids": {
    6. "type": "_doc",
    7. "values":["axEwmoEBTXtCd1dvuDqv","gxHImYEBTXtCd1dv3Dfj"]
    8. }
    9. }
    10. }

    二、全文检索

    我们知道 keyword 类型不支持分词,该类型的字段使用全文检索时,必须使用全部字符串匹配才能被查找到;而 text 类型的字段适合于全文检索,支持分词,同时要考虑具体分词器,因为不同的分词器对相同的文本字符长的分解词项可能不一样。

    下面使用 wheater_infos_2022 索引演示,在该索引里新增了6.1号~6.3号、四座城市的共12条天气记录数据~

    1、匹配搜索(match query)

    match 匹配查询,查询时会分词处理,接受文本/数字/日期等数据类型。

    1. # today_weather.temperature_range,该字段是text类型
    2. # temperature_range 原文本字符串为"26-344℃",此处会使用到默认的standard分词方式
    3. # 匹配 today_weather.temperature_range 包含 26 或 44
    4. GET wheater_infos_2022/_search?pretty&track_total_hits=true
    5. {
    6. "query": {
    7. "match": {
    8. "today_weather.temperature_range": "26 44"
    9. }
    10. }
    11. }
    12. # 上面的写法看不明白?上面的写法等同于下面的这种写法:
    13. GET wheater_infos_2022/_search?pretty&track_total_hits=true
    14. {
    15. "query": {
    16. "match": {
    17. "today_weather.temperature_range": {
    18. "query": "26 44",
    19. "operator": "or" //默认or操作
    20. }
    21. }
    22. }
    23. }

    如果需要了解更多的参数设置(比如 fuzziness/zero_terms_query/cutoff_frequency 等),可参考官网文档:Match Query | Elasticsearch Guide [6.8] | Elastic

    2、匹配解析搜索(match_phrase query)

    match_phrase 查询分析文本,并从分析文本中创建分词(该查询方式,首先将查询的文本字符串解析成一个词项列表,然后对这些词项进行搜索,但只保留那些包含全部搜索词项,且位置与搜索词项相同的文档)。

    请注意,这句话的理解,只保留那些包含全部搜索词项,位置与搜索词项相同的文档,也就是说,我把 today_weather.temperature_range 的 "26 344",修改成 "344 26",返回查询的结果则会为空。

    1. GET wheater_infos_2022/_search?pretty&track_total_hits=true
    2. {
    3. "query": {
    4. "match_phrase": {
    5. "today_weather.temperature_range": "26 344"
    6. }
    7. }
    8. }

    如果需要了解更多的参数设置(比如 analyzer),可参考官网文档:Match Phrase Query | Elasticsearch Guide [6.8] | Elastic

    3、匹配解析前缀搜索(match_phrase_prefix query)

    match_phrase_prefix 与 match_phrase 原理相同,不同的是 match_phrase_prefix 允许文本中最后一个术语可以前缀匹配。

    1. GET wheater_infos_2022/_search?pretty&track_total_hits=true
    2. {
    3. "query": {
    4. "match_phrase_prefix": {
    5. "today_weather.temperature_range": "34*"
    6. }
    7. }
    8. }

    如果需要了解更多的参数设置(比如 max_expansions),可参考官网文档:Match Phrase Prefix Query | Elasticsearch Guide [6.8] | Elastic

    4、多字段匹配搜索(multi_math query)

    multi_math 能在多个字段上反复执行相同的查询。默认情况下,查询的类型是 best_fields(它会为每个字段生成一个 match 查询),也支持 most_fields、cross_fields、phrase、phrase_prefix 等查询类型。

    1. GET wheater_infos_2021/_search?pretty&track_total_hits=true
    2. {
    3. "query": {
    4. "multi_match": {
    5. "query": "26 AND 344", //查询字符串,支持指定AND | OR | NOT条件
    6. "fields": [
    7. "today_weather.temperature",
    8. "today_weather.temperature_*",
    9. "today_weather.pm_value^2" //^2表示提示查询该字段的权重
    10. ]
    11. }
    12. }
    13. }

    如果需要了解更多的参数设置(比如 type/tie_breaker 等),可参考官网文档:Multi Match Query | Elasticsearch Guide [6.8] | Elastic

    5、匹配搜索(query_string query)

    query_string 许在单个查询字符串中指定AND | OR | NOT条件,同时也和 multi_match query 一样,支持多字段搜索。

    请注意,query_string 不支持 keyword 类型字段查询,返回的查询结果则为空,query_string 适用于查询 text 类型的字段,且查询的分词和顺序无关,分词也不需要连续,比如 "query" 使用 "26 AND 344"  和  "344 AND 26" 查询效果是一样的!

    1. GET wheater_infos_2021/_search?pretty&track_total_hits=true
    2. {
    3. "query": {
    4. "query_string": {
    5. "query": "26 AND 344", //查询字符串,支持指定AND | OR | NOT条件
    6. "fields": [
    7. "today_weather.temperature"
    8. ]
    9. }
    10. }
    11. }
    12. GET wheater_infos_2021/_search?pretty&track_total_hits=true
    13. {
    14. "query": {
    15. "query_string": {
    16. "query": "26 AND 344", //查询字符串,支持指定AND | OR | NOT条件
    17. "fields": [
    18. "today_weather.temperature",
    19. "today_weather.temperature_*",
    20. "today_weather.pm_value^2" //^2表示提示查询该字段的权重
    21. ]
    22. }
    23. }
    24. }

    如果需要了解更多的参数设置,可参考官网文档:Query String Query | Elasticsearch Guide [6.8] | Elastic

    6、简单字符串搜索(simple_query_string query)

    与 query_string 相比,simple_query_string 不会抛出异常,并丢弃查询的无效部分,不支持使用 AND、OR、NOT 作为连接符,而是支持下面这些方式:

    • + 表示与运算,相当于query_string 的 AND;
    • | 表示或运算,相当于query_string  的 OR(默认);
    • - 表示取反运算,相当于query_string 的 NOT;
    • "" 表示对检索词进行 match_phrase query;
    • * 字词末尾表示前缀查询;
    • ( and )表示优先级;
    1. GET wheater_infos_2021/_search?pretty&track_total_hits=true
    2. {
    3. "query": {
    4. "simple_query_string": {
    5. "query": "26 + 34", //查询字符串,+相当于query_string的AND
    6. "fields": [
    7. "today_weather.temperature",
    8. "today_weather.temperature_*",
    9. "today_weather.pm_value^2" //^2表示提示查询该字段的权重
    10. ]
    11. }
    12. }
    13. }

    如果需要了解更多的参数设置,可参考官网文档: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 版本,并结合官方文档加以学习和使用。

  • 相关阅读:
    axios详解以及完整封装方法
    idea设置格式化竖线
    使用CLion和gdb server debug haproxy
    如何在Android项目中制作和使用三方包(jar文件)
    mybatis config 配置
    Java中的内部类(如果想知道Java中有关内部类的知识点,那么只看这一篇就足够了!)
    Spring MVC BeanNameViewResolver原理解析
    如何使用 Junit + Mockito 实践单元测试
    用栈模拟队列
    Java基础—Node类型的变化
  • 原文地址:https://blog.csdn.net/qq_29119581/article/details/114713597