当前位置: 首页 > news >正文

分布式专题——46 ElasticSearch高级查询语法Query DSL实战

1 概述与数据准备

  • Query DSL 是 Elasticsearch 提供的领域专用语言(Domain Specified Language),通过 Rest API 传递 JSON 格式的请求体(RequestBody) 与 ES 交互,具备丰富的查询语法,让数据检索更强大、简洁;

  • 官方文档链接:[Query DSL | Elasticsearch Guide 8.14] | Elastic;

  • 基本语法:用于对指定索引执行检索操作

    GET /<index_name>/_search {json请求体数据}
    
  • 数据准备:

    DELETE /employee
    PUT /employee
    {"settings": {"number_of_shards": 1,"number_of_replicas": 1},"mappings": {"properties": {"name": {"type": "keyword" # keyword 类型适用于精确匹配,不进行分词},"sex": {"type": "integer"},"age": {"type": "integer"},"address": { # 主类型为 text,并指定分词器为 ik_max_word(IK 分词器的“细粒度分词”模式,尽可能拆分出更多词汇)"type": "text","analyzer": "ik_max_word","fields": { # 多字段映射 fields.keyword:类型为 keyword,用于对 address 进行精确匹配场景"keyword": {"type": "keyword"}}},"remark": {"type": "text", # 主类型为 text,指定分词器为 ik_smart(IK 分词器的“粗粒度分词”模式,拆分出相对少而关键的词汇)"analyzer": "ik_smart","fields": { # 多字段映射 fields.keyword:类型为 keyword,用于精确匹配场景"keyword": {"type": "keyword"}}}}}
    }# 批量导入多条文档,每两条 JSON 为一组(第一条是操作描述,第二条是文档内容)
    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"}
    

    在 ElasticSearch 中,多字段映射(Multi-fields Mapping) 是一种让一个字段同时拥有多种数据类型或分词策略的技术,以便在不同业务场景下(精确匹配、模糊检索、聚合分析等)灵活使用该字段;

    address 字段为例,业务中可能同时存在两种需求:

    • 需求一:模糊检索(如搜索“广州”,希望匹配到“广州天河公园”“广州荔湾大厦”等包含“广州”的地址)
    • 需求二:精确匹配(如搜索“广州天河公园”,仅希望匹配完全一致的地址)

    如果只给 address 定义一种类型,无法同时满足这两种场景。此时就需要多字段映射

    "address": {"type": "text","analyzer": "ik_max_word","fields": {"keyword": {"type": "keyword"}}
    }
    
    • 主字段 address:类型是 text,分词器为 ik_max_word(细粒度分词),用于模糊检索场景(比如全文搜索“广州”,能匹配到所有包含“广州”的地址)
    • 子字段 address.keyword:类型是 keyword(不分词,精确存储原始值),用于精确匹配场景(比如筛选地址为“广州天河公园”的文档,或对地址进行聚合统计)

2 match_all:匹配所有文档

2.1 match_all 查询

  • match_all 是 Elasticsearch 中用于匹配索引中所有文档的特殊查询类型,不附加任何查询条件;

  • 基本语法

    GET /<your-index-name>/_search
    {"query": {"match_all": {}}
    }
    
  • 高级用法(结合评分排序和结果条数):可通过 size 控制返回文档数,通过 sort 排序。示例:

    GET /<your-index-name>/_search
    {"query": {"match_all": {}},"size": 10,"sort": [{"_score": {"order": "desc"}}]
    }
    

2.2 _source 字段控制

  • _source 用于控制查询结果中是否返回原始文档数据,支持灵活的字段过滤策略;

  • 不返回源数据,仅查元字段

    GET /<your-index-name>/_search
    {"query": {"match_all": {}},"_source": false
    }
    
  • 返回指定字段:仅返回 field1field2 字段的内容

    GET /<your-index-name>/_search
    {"query": {"match_all": {}},"_source": ["field1","field2"]
    }
    
  • 返回匹配前缀的字段:仅返回以 obj. 开头的字段(如 obj.nameobj.age 等)

    GET /<your-index-name>/_search
    {"query": {"match_all": {}},"_source": "obj.*"
    }
    

2.3 结果分页(sizefrom

  • 用于控制查询结果的条数和分页,实现类似数据库的分页查询;

  • size 返回指定条数:仅返回 3 条文档

    GET /employee/_search
    {"query": {"match_all": {}},"size": 3
    }
    
  • from&size 分页查询from 表示“跳过前 N 条”,size 表示“返回 M 条”。下面示例代码中“跳过 0 条,返回 5 条”,即第 1-5 条文档

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

2.4 排序(sort

  • 用于指定字段的排序规则(升序 asc 或降序 desc),支持多字段组合排序;

  • 根据单个字段排序:按 age 降序排列

    GET /employee/_search
    {"query": {"match_all": {}},"sort": [{"age": "desc"}]
    }
    
  • 排序同时分页:先按 age 降序,再跳过 2 条、返回 5 条

    GET /employee/_search
    {"query": {"match_all": {}},"sort": [{"age": "desc"}],"from": 2,"size": 5
    }
    
  • 结合 _source 过滤字段排序:排序的同时,仅返回 nameaddress 字段

    GET /employee/_search
    {"query": {"match_all": {}},"_source": ["name","address"]
    }
    

3 精确匹配

  • 精确匹配是指搜索内容不经过文本分析,直接用于文本匹配,类似数据库的 SQL 精确查询;
  • 它主要适用于结构化数据(如 ID、状态、标签等),且搜索对象多为索引的 non-text 类型字段(如 keywordinteger 等)。

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

  • term 查询用于单字段的精准匹配场景

  • 适用字段:仅适用于未经过分词处理的 keyword 类型字段(若用于 text 类型字段,不会报错,但结果通常不符合预期,因为 text 字段会被分词);

  • 基本语法

    GET /{index_name}/_search
    {"query": {"term": {"{field.keyword}": {"value": "your_exact_value"}}}
    }
    
    • 其中,{index_name} 是索引名,{field.keyword}keyword 类型的字段(如下面示例中的 nameaddress.keyword),value 是要精确匹配的值;
  • term 查询的示例与注意事项

    • 示例1:匹配 keyword 类型字段(正确用法)。查询姓名为“张三”的员工(name 字段是 keyword 类型):

      GET /employee/_search
      {"query": {"term": {"name": {"value": "张三"}}}
      }
      
    • 示例2:误用 text 类型字段(错误示范)。若直接对 addresstext 类型)执行 term 查询“广州白云”,会因 address 被分词(如拆分为“广州”“白云”等)而无法匹配到“广州白云山公园”这条数据:

      GET /employee/_search
      {"query":{"term": {"address": {"value": "广州白云"}}}
      }
      
    • 示例3:正确使用 text 字段的 keyword 多字段。对 addresskeyword 多字段 address.keyword 执行精确匹配“广州白云山公园”,即可命中数据:

      GET /employee/_search
      {"query":{"term": {"address.keyword": {"value": "广州白云山公园"}}}
      }
      
  • term 处理多值字段(数组)的逻辑

    • 当字段是多值数组(如 interest: ["跑步","篮球"])时,term 查询的匹配逻辑是**“包含”而非“等于”**;

    • 示例:批量导入 people 索引的多值文档后,查询 interest.keyword 包含“跑步”的文档,会匹配到 interest["跑步","篮球"]["跳舞","唱歌","跑步"] 的两条数据:

      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": "跑步"}}}
      }
      
  • term 查询的性能优化(constant_scoreterm 查询默认会进行相关度算分(如 TF-IDF),但在仅需“精确过滤”的场景下,算分是额外开销。可通过 constant_score 将其转换为 filter,实现以下优化:

    • 忽略 TF-IDF 算分,减少性能开销;

    • 利用 Elasticsearch 的缓存机制,提升后续查询速度;

    • 示例:

      GET /employee/_search
      {"query": {"constant_score": {"filter": {"term": {"address.keyword": "广州白云山公园"}}}}
      }
      

3.2 terms 查询——多值精确匹配

  • terms 检索是 Elasticsearch 中用于多值精准匹配的查询方式,允许在单个查询中指定多个词条对字段进行精确匹配。它针对未分析的字段(如 keyword、数字、日期等结构化数据字段)生效,适用于筛选包含多个特定值的场景(如多标签、多状态的文档);

  • 适合从文档中查找包含多个特定值的字段,典型场景包括:

    • 筛选具有多个特定标签的内容(如同时匹配“标签A”和“标签B”的文档)

    • 匹配多个状态值(如“待处理”“已完成”的任务)

    • 对数字、日期等结构化数据的多值精确检索

  • 在 Elasticsearch 8.x 中,terms 查询的语法结构如下:

    GET /<index_name>/_search
    {"query": {"terms": {"<field_name>": ["value1","value2","value3",...]}}
    }
    
    • <index_name>:要查询的索引名称;

    • <field_name>:要执行 terms 查询的字段名(需为 keyword 或其他未分词的结构化字段类型);

    • 方括号内的 value1, value2...:希望匹配的多个精确值列表;

  • employee 索引的 remark.keyword 字段为例,查询同时匹配“java assistant”和“java architect”的文档:

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

3.3 range 查询——范围查询

  • range 检索是 Elasticsearch 中用于指定字段值在给定范围内的文档检索类型,适用于数字、日期或其他可排序数据类型的字段,支持 gt(大于)、gte(大于等于)、lt(小于)、lte(小于等于)等比较操作符,实现灵活的区间查询;

  • 在 Elasticsearch 8.x 中,range 查询的语法结构如下:

    GET /<index_name>/_search
    {"query": {"range": {"<field_name>": {"gte": <lower_bound>,"lte": <upper_bound>,"gt": <greater_than_bound>,"lt": <less_than_bound>}}}
    }
    
    • <index_name>:要查询的索引名称

    • <field_name>:要执行 range 查询的字段名(需为数字、日期等可排序类型)

    • gte:大于等于(Greater Than or Equal)

    • lte:小于等于(Less Than or Equal)

    • gt:严格大于(Greater Than)

    • lt:严格小于(Less Than)

    • <lower_bound> 等:指定的数值或日期边界

  • employee 索引的 age 字段为例,查询年龄在 25 到 28 之间(包含 25 和 28)的员工:

    POST /employee/_search
    {"query": {"range": {"age": {"gte": 25,"lte": 28}}}
    }
    
  • 日期范围查询(含测试数据准备)

    • 生成测试数据:创建 notes 索引,定义 created_atdate 类型(格式 yyyy-MM-dd HH:mm:ss),并批量导入带创建日期的笔记文档

      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"}
      
    • 查询 created_at 在 2023-07-05 到 2023-07-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 小时。

    • 示例:查询 product 索引中,date 在“当前时间前推 2 年”之后的产品文档:

      GET /product/_search
      {"query": {"range": {"date": {"gte": "now-2y"}}}
      }
      

3.4 exists——是否存在查询

  • exists 检索用于筛选具有特定字段值的文档,判断文档中是否存在某个字段,或该字段是否包含非空值。它能有效过滤缺少关键信息的文档,聚焦包含所需数据的结果;

  • 典型场景包括:

    • 数据完整性检查(如筛选包含“联系方式”字段的用户文档)

    • 查询具有特定属性的文档(如包含“标签”字段的内容)

    • 对可选字段进行筛选(如区分有“备注”和无“备注”的订单)

  • 基本语法:

    GET /<index_name>/_search
    {"query": {"exists": {"field": "missing_field"}}
    }
    
    • <index_name>:要查询的索引名称

    • field:指定要检查是否存在的字段名

  • employee 索引为例,查询存在 remark 字段的文档:

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

3.5 ids——根据一组id查询

  • ids 检索是 Elasticsearch 中用于根据一组文档 ID 快速召回相关数据的查询方法,能高效实现特定文档的检索,尤其适用于已知具体文档 ID 的场景;

  • 典型场景包括:

    • 已知多个文档 ID,需批量获取这些文档的详细信息

    • 基于业务逻辑(如用户收藏、订单列表)中记录的 ID 集合,快速检索对应文档

  • 基本语法

    GET /<index_name>/_search
    {"query": {"ids": {"values": ["id1", "id2", "id3", ...]}}
    }
    
    • <index_name>:要查询的索引名称

    • values:指定要检索的文档 ID 列表(支持字符串、数字等 ID 类型)

  • employee 索引为例,查询 ID 为 12 的员工文档:

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

3.6 prefix——前缀匹配

  • prefix 查询是对分词后的 term 进行前缀搜索,具有以下关键特性:

    • 不会对搜索的字符串分词,传入的前缀就是要查找的前缀

    • 默认不计算相关性分数,所有匹配文档的相关分数均为 1

    • 原理是遍历所有倒排索引,比较每个词项是否以指定前缀开头

  • 用于搜索指定字段中以特定前缀开头的文档,语法结构如下:

    GET /<index_name>/_search
    {"query": {"prefix": {"your_field_name": {"value": "your_prefix_string"}}}
    }
    
    • <index_name>:目标索引名称

    • your_field_name:要检索的字段名(仅适用于 keyword 类型字段

    • your_prefix_string:要匹配的前缀字符串

  • 适用场景:常用于自动补全、搜索提示等功能(如用户输入“java”,提示“java developer”“java architect”等);

  • 字段限制:仅适用于 keyword 类型字段(若用于 text 类型字段,因分词机制会导致结果不符合预期);

  • employee 索引的 address 字段为例,对比两种查询方式的差异:

    • 错误示例(使用 text 类型的 address 字段)

      GET /employee/_search
      {"query": {"prefix": {"address": {"value": "广州白云山"}}}
      }
      
      • addresstext 类型(会分词),该查询无法命中“广州白云山公园”这类文档(分词后“广州白云山”不是独立词项);
    • 正确示例(使用 keyword 类型的 address.keyword 字段)

      GET /employee/_search
      {"query": {"prefix": {"address.keyword": {"value": "广州白云山"}}}
      }
      
      • address.keywordkeyword 类型(不分词,存储原始值),因此能匹配到“广州白云山公园”这类以“广州白云山”为前缀的文档。

3.7 wildcard——通配符匹配

  • wildcard 检索是 Elasticsearch 中支持通配符匹配的查询类型,允许通过通配符表达式匹配文档的字段值,适用于对“部分已知内容的文本字段”进行模糊检索(如文件名、产品型号等有规律的字段);

  • 通配符规则

    • 星号(*):表示零或多个字符,可匹配任意长度的字符串

    • 问号(?):表示一个字符,可匹配任意单个字符

  • 适用场景:对部分已知、有规律的字段进行模糊检索(如“产品型号以 ABC* 开头”“文件名包含 ??.pdf”等场景);

  • 性能注意事项:通配符查询可能带来较高的计算负担,尤其是在海量文档场景下,需谨慎使用;

  • 基本语法

    GET /<index_name>/_search
    {"query": {"wildcard": {"your_field_name": {"value": "your_search_pattern"}}}
    }
    
    • <index_name>:目标索引名称

    • your_field_name:要检索的字段名(通常为 keyword 类型,确保精确匹配通配符模式)

    • your_search_pattern:包含通配符(*?)的检索模式

  • employee 索引的 address.keyword 字段为例,查询地址中包含“州”且以“公园”结尾的文档:

    GET /employee/_search
    {"query": {"wildcard": {"address.keyword": {"value": "*州*公园"}}}
    }
    

3.8 regexp——正则匹配查询

  • regexp 检索是一种基于正则表达式的检索方法,功能强大但性能开销较高,建议非必要情况下避免使用,以保证查询性能的高效稳定。它比 wildcard 查询更灵活强大,可用于搜索满足特定模式的文本;

  • 用于在指定字段中执行正则表达式匹配,语法结构如下:

    GET /<index_name>/_search
    {"query": {"regexp": {"your_field_name": {"value": "your_search_pattern"}}}
    }
    
    • <index_name>:目标索引名称

    • your_field_name:要检索的字段名

    • your_search_pattern:正则表达式模式(需符合 Elasticsearch 支持的正则语法)

  • 适用场景:需对文本进行复杂模式匹配的场景(如匹配特定格式的手机号、邮箱,或符合自定义规则的字符串);

  • 性能建议:因正则表达式的计算开销大,非必要时避免使用,优先选择 matchterm 等轻量查询;

  • employee 索引的 remark 字段为例,查询 remark 中以 java. 开头、后续跟任意字符的文档:

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

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

  • fuzzy 检索是一种支持编辑距离的模糊查询功能,可在用户输入存在拼写错误或上下文不一致时,返回与搜索词相似的文档。它通过编辑距离算法度量输入词与文档词条的相似程度,兼顾搜索结果相关性与容错能力;

  • 编辑距离是指“从一个单词转换到另一个单词需要编辑单字符的次数”。例如:

    • “中文集团”到“中威集团”编辑距离为 1(仅需修改一个字符);

    • fuzziness 设为 2,还会匹配编辑距离为 2 的“东东集团”;

  • 基本语法与参数说明:

    GET /<index_name>/_search
    {"query": {"fuzzy": {"your_field": {"value": "search_term","fuzziness": "AUTO","prefix_length": 1}}}
    }
    
    • fuzziness:用于设置编辑距离,默认值为 AUTO,支持数值 [0, 1, 2](超出范围会报错);

    • prefix_length:搜索词的前缀长度,在此长度内不应用模糊匹配(默认 0,即整个词都模糊匹配);

  • employee 索引的 address 字段为例,查询与“白运山”编辑距离为 1 的文档:

    GET /employee/_search
    {"query": {"fuzzy": {"address": {"value": "白运山","fuzziness": 1}}}
    }
    

3.10 terms_set——解决多值字段中的文档匹配问题

  • terms_set 检索是 Elasticsearch 中用于解决多值字段文档匹配问题的检索类型,能处理具有多个属性、分类或标签的复杂数据。它允许检索“至少匹配指定数量词项”的文档,匹配数量可设为固定值或基于其他字段/脚本动态计算

  • 适用于多值字段的精细匹配场景,典型场景包括:

    • 标签系统(如筛选同时包含多个标签的内容)

    • 技能匹配(如招聘中匹配满足一定技能数量的候选人)

    • 电子商务系统(如筛选具有多个属性的商品)等

  • 基本语法与参数说明

    GET /<index_name>/_search
    {"query": {"terms_set": {"<field_name>": {"terms": ["<term1>", "<term2>", ...],"minimum_should_match_field": "<字段名>" or"minimum_should_match_script": {"source": "<脚本>"}}}}
    }
    
    • <field_name>:要查询的多值字段(通常为 keyword 类型)

    • terms:用于匹配的词项列表

    • minimum_should_match_field:指定一个字段,其值作为“最少需要匹配的词项数”

    • minimum_should_match_script:通过自定义脚本动态计算最少需要匹配的词项数

  • 创建 movies 索引,定义多值字段 tagskeyword 类型)和用于动态匹配的 tags_countinteger 类型),并批量导入测试文档:

    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 进行匹配

    • 方式1:通过 minimum_should_match 指定固定匹配数(如至少匹配 2 个词项):

      GET /movies/_search
      {"query": {"terms_set": {"tags": {"terms": ["喜剧", "动作", "科幻"],"minimum_should_match": 2}}}
      }
      
      • 该查询会匹配 tags 中至少包含“喜剧、动作、科幻”中 2 个词项的文档(如“电影1”包含 3 个,“电影3”包含“动作、科幻”2 个,均会命中);
    • 方式2:通过 minimum_should_match_script 脚本指定固定匹配数(如脚本返回“2”):

      GET /movies/_search
      {"query": {"terms_set": {"tags": {"terms": ["喜剧", "动作", "科幻"],"minimum_should_match_script": {"source": "2"}}}}
      }
      
      • 效果与上述 minimum_should_match: 2 一致;
  • 使用动态计算的 term 数量进行匹配

    • 方式1:通过 minimum_should_match_field 关联字段(如 tags_count),以字段值作为匹配数:

      GET /movies/_search
      {"query": {"terms_set": {"tags": {"terms": ["喜剧", "动作", "科幻"],"minimum_should_match_field": "tags_count"}}}
      }
      
      • tags_count 为 3,该查询要求 tags 至少匹配 3 个词项,仅“电影1”会命中。
    • 方式2:通过 minimum_should_match_script 动态计算匹配数(如 tags_count * 0.7):

      GET /movies/_search
      {"query": {"terms_set": {"tags": {"terms": ["喜剧", "动作", "科幻"],"minimum_should_match_script": {"source": "doc['tags_count'].value*0.7"}}}}
      }
      
      • 计算得 3 * 0.7 ≈ 2.1(向下取整为 2),即要求至少匹配 2 个词项,“电影1”“电影3”会命中。

4 全文检索

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

4.1 match——分词查询

  • match 查询是一种全文搜索查询,底层逻辑分为三步:

    • 分词:输入的查询文本会被分词器拆分为单个词项(如“广州白云山公园”会被拆分为“广州”“白云山”“公园”等词项,分词规则由字段的分词器决定)

    • 匹配计算:Elasticsearch 会对比查询词项与倒排索引中的词项,计算文档的相关性得分(衡量文档与查询的匹配程度)

    • 结果返回:按相关性得分排序,返回最匹配的文档

  • 基本语法

    GET /<index_name>/_search
    {"query": {"match": {"<field_name>": "<query_string>"}}
    }
    
    • <index_name>:目标索引名称

    • <field_name>:要检索的文本字段(如 addressremark 等)

    • <query_string>:要搜索的文本字符串

  • employee 索引的 address 字段为例,分析不同 match 查询的行为:

    • 分词后“或(OR)”的效果(默认行为)

      GET /employee/_search
      {"query": {"match": {"address": "广州白云山公园"}}
      }
      
      • address 字段的分词器是 ik_max_word,会将“广州白云山公园”拆分为多个词项(如“广州”“白云山”“公园”等);
      • match 查询默认采用“或”逻辑,只要文档包含任意一个词项就会匹配,因此会返回包含“广州”“白云山”“公园”中任意一个词项的文档;
    • 分词后“与(AND)”的效果(通过 operator 参数控制)

      GET /employee/_search
      {"query": {"match": {"address": {"query": "广州白云山公园","operator": "and"}}}
      }
      
      • operator 参数设为 and 后,要求文档同时包含所有分词后的词项才会匹配,因此只有同时包含“广州”“白云山”“公园”的文档才会命中;
    • 最少匹配词项数(通过 minimum_should_match 参数控制)

      GET /employee/_search
      {"query": {"match": {"address": {"query": "广州公园","minimum_should_match": 2}}}
      }
      
      • minimum_should_match 参数用于控制至少需要匹配的分词数量
      • 此例中要求至少匹配“广州”“公园”这 2 个词项,因此只有同时包含这两个词项的文档才会返回。

4.2 multi_match——多字段查询

  • multi_match 查询用于在多个字段上执行相同的搜索操作,接收一个查询字符串,在指定的字段集合中检索该字符串。它支持灵活的匹配类型和操作符,可根据不同搜索需求调整行为,适用于需要跨多个字段进行全文检索的场景;

  • 基本语法:

    GET /<index_name>/_search
    {"query": {"multi_match": {"query": "<query_string>","fields": ["<field1>", "<field2>", ...]}}
    }
    
    • <index_name>:要搜索的索引名称

    • <query_string>:要在多个字段中搜索的字符串

    • <field1>, <field2>, ...:要搜索的字段列表(支持多个文本字段)

  • employee 索引为例,查询同时在 addressremark 字段中包含“长沙java”的文档:

    GET /employee/_search
    {"query": {"multi_match": {"query": "长沙java","fields": ["address","remark"]}}
    }
    
    • 该查询会对“长沙java”进行分词(如拆分为“长沙”“java”),然后在 address 字段(文本类型,分词器 ik_max_word)和 remark 字段(文本类型,分词器 ik_smart)中分别检索这些词项,最终返回在任一字段中匹配到词项的文档(并按相关性得分排序)。

4.3 match_phrase——短语查询

  • match_phrase 查询用于执行短语搜索,不仅匹配整个短语,还会严格考虑短语中各个词的顺序和位置。它适用于需要精确匹配短语的场景(如用户查询需与文档文本表达方式严格一致时);

  • 基本语法

    GET /<index_name>/_search
    {"query": {"match_phrase": {"<field_name>": {"query": "<phrase>"}}}
    }
    
    • <index_name>:目标索引名称

    • <field_name>:要检索的文本字段

    • <phrase>:要搜索的精确短语

  • 通过分词分析理解 match_phrase 的匹配规则:

    • 对“广州白云山”使用 ik_max_word 分词器,结果为 ["广州", "白云山", "白云", "云山"],各词的 position(位置)分别为 0123

      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}]
      }
      
    • match_phrase 默认要求词项严格相邻且顺序一致。例如:

      • 查询“广州白云山”时,因“广州”(position 0)和“白云山”(position 1)相邻,能匹配到包含该短语的文档;
      • 查询“广州白云”时,“广州”(position 0)和“白云”(position 2)不相邻,因此无匹配结果;
  • 对于以上问题,可以使用**slop 参数**;

    • 该参数用于指定短语中词之间允许的最大位移数量(默认 0,即严格相邻)。若设置非零 slop,则允许词项在一定范围内错位;

    • 示例:查询“广州云山”时,“广州”(position 0)和“云山”(position 3)间隔为 3,通过设置 slop: 2 允许位移,即可匹配到结果:

      GET /employee/_search
      {"query": {"match_phrase": {"address": {"query": "广州云山","slop": 2}}}
      }
      

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

  • query_string 是一种灵活的复杂查询类型,支持使用 Lucene 查询语法构建检索逻辑,具备以下特性:

    • 支持逻辑运算符:AND(与)、OR(或)、NOT(非)

    • 支持通配符、模糊搜索、正则表达式等高级功能

    • 可在单个或多个字段上执行搜索,能处理复杂查询逻辑

  • 适用于高级搜索、数据分析、报表等场景,尤其适合需满足“与或非”复杂逻辑的专业领域或高级查询需求;

  • 基本语法

    GET /<index_name>/_search
    {"query": {"query_string": {"query": "<your_query_string>","default_field": "<field_name>"}}
    }
    
    • <your_query_string>:包含逻辑运算符、通配符等的查询逻辑

    • <default_field>:默认搜索字段(省略则搜索所有可索引字段)

  • employee 索引为例,分三类场景解读:

    • 未指定字段查询:查询所有可索引字段中满足“赵六 AND 橘子洲”的文档(AND 需大写)

      GET /employee/_search
      {"query": {"query_string": {"query": "赵六 AND 橘子洲"}}
      }
      
      • 该查询会在所有可索引字段中检索同时包含“赵六”和“橘子洲”的文档;
    • 指定单个字段查询:在 address 字段中查询包含“白云山”或“橘子洲”的文档

      GET /employee/_search
      {"query": {"query_string": {"default_field": "address","query": "白云山 OR 橘子洲"}}
      }
      
      • 注意:字段的分词特性会影响查询行为——若字段分词(如 addresstext 类型,用 ik_max_word 分词),查询条件会按分词逻辑检索;若字段不分词(如 keyword 类型),则按精确逻辑检索;
    • 指定多个字段查询:在 nameaddress 字段中执行复杂逻辑查询:“张三” 或 “(广州 AND 王五)”

      GET /employee/_search
      {"query": {"query_string": {"fields": ["name","address"],"query": "张三 OR (广州 AND 王五)"}}
      }
      
      • 该查询会在 name 字段匹配“张三”,或在 address 字段同时匹配“广州”和“王五”的文档中命中结果。

4.5 simple_query_string

  • simple_query_stringquery_string 的“容错版”,具备以下特点:

    • 忽略错误语法:即使查询语法有问题,也不会导致查询失败

    • 支持部分逻辑:不支持 AND OR NOT 关键字(会被当作普通字符串),改用特殊符号替代逻辑运算

    • 生产环境推荐:因语法宽松、容错性强,适合生产环境使用

  • 支持的逻辑运算符(替代 query_string 的关键字)

    • +:替代 AND(表示“必须包含”)

    • |:替代 OR(表示“或包含”)

    • -:替代 NOT(表示“必须不包含”)

  • 基本语法

    GET /<index_name>/_search
    {"query": {"simple_query_string": {"query": "<query_string>","fields": ["<field1>", "<field2>", ...],"default_operator": "OR" // 或 "AND"}}
    }
    
    • <query_string>:包含逻辑运算符(+ | -)的查询表达式

    • fields:指定搜索的字段列表

    • default_operator:未指定运算符时的默认逻辑(OR 表示“或”,AND 表示“与”)

  • employee 索引为例,解读两种查询场景:

    • 通过 default_operator 指定默认逻辑。在 nameaddress 字段中,要求同时包含“广州”和“公园”(默认运算符设为 AND):

      GET /employee/_search
      {"query": {"simple_query_string": {"fields": ["name","address"],"query": "广州公园","default_operator": "AND"}}
      }
      
    • 通过 + 显式指定“与”逻辑。在 nameaddress 字段中,显式要求同时包含“广州”和“公园”(用 + 替代 AND):

      GET /employee/_search
      {"query": {"simple_query_string": {"fields": ["name","address"],"query": "广州 + 公园"}}
      }
      

4.6 小结

  • 精确匹配与全文检索的本质区别,主要体现在以下两个方面:

    • 精确匹配:不对检索文本进行分词处理,将整个文本视为一个完整的词条进行匹配。例如 term 查询对 keyword 类型字段的匹配,直接以原始字符串为单位进行精确比对;

    • 全文检索:需要对文本进行分词处理,分词后每个词条将单独进行检索,并通过布尔逻辑(如与、或、非等)进行组合检索,以找到最相关的结果。例如 match 查询会先将查询文本分词,再在倒排索引中对分词后的词条进行关联检索和相关性算分。

5 bool query布尔查询

  • 布尔查询(bool query)通过布尔逻辑条件组织多条查询语句,只有符合整个布尔条件的文档才会被检索出来,是 Elasticsearch 实现复杂查询逻辑的核心工具;

  • 布尔查询包含两种不同的执行上下文,决定了查询的性能和相关性计算方式:

    • 搜索上下文(query context):需计算文档与搜索条件的相关度得分(通过复杂公式计算,有性能开销),适合带文本分析的全文检索场景(如 match 查询);

    • 过滤上下文(filter context):仅判断文档是否匹配条件,不计算相关度得分,且结果可缓存以加快响应,适合术语级精确匹配场景(如 termrange 查询);

  • 布尔查询的4种组合类型:

    类型说明上下文类型
    must包含的所有查询条件必须全部满足,需计算相关度得分搜索上下文
    should若不存在 must/filter,则至少满足一个条件;匹配越多相关度越高搜索上下文
    filter包含的所有过滤条件必须全部满足,不计算相关度得分,结果可缓存过滤上下文
    must_not包含的所有过滤条件必须全部不满足,不计算相关度得分,结果可缓存过滤上下文
  • 例:

    • 索引与数据准备。创建 books 索引,定义字段映射(如 titletext 类型、languagekeyword 类型等),并批量导入图书文档:

      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技术经典名著"}
      
    • must 组合示例(多条件必须满足,计算相关度)。查询 title 包含“java编程” description 包含“性能优化”的图书:

      GET /books/_search
      {"query": {"bool": {"must": [{ "match": { "title": "java编程" } },{ "match": { "description": "性能优化" } }]}}
      }
      
      • 仅“Java程序性能优化”会命中(同时满足两个条件),且会按相关度得分排序;
    • should 组合示例(至少满足一个条件,计算相关度)。查询 title 包含“java编程” description 包含“性能优化”的图书,且要求至少满足 1 个条件:

      GET /books/_search
      {"query": {"bool": {"should": [{ "match": { "title": "java编程" } },{ "match": { "description": "性能优化" } }],"minimum_should_match": 1}}
      }
      
      • “Java编程思想”(满足 title 条件)、“Java程序性能优化”(满足两个条件)都会命中,匹配越多的文档相关度得分越高;
    • filter 组合示例(多条件必须满足,不计算得分,可缓存)。查询 language 为“java” publish_time 大于等于“2010-08-01”的图书:

      GET /books/_search
      {"query": {"bool": {"filter": [{ "term": { "language": "java" } },{ "range": { "publish_time": { "gte": "2010-08-01" } } }]}}
      }
      
      • “Java程序性能优化”(publish_time 为 2012-08-01)会命中,该查询不计算相关度得分,且 filter 条件可被缓存以提升后续查询速度。

6 highlight高亮

  • highlight 关键字用于将符合查询条件的文档中匹配的关键词进行高亮标记,提升搜索结果的可读性,帮助用户快速定位匹配内容;

  • highlight 相关属性

    • pre_tags:高亮内容的前缀标签(如 HTML 标签的开始部分)

    • post_tags:高亮内容的后缀标签(如 HTML 标签的结束部分)

    • tags_schema:设置为 styled 时,可使用 Elasticsearch 内置的高亮样式

    • require_field_match:多字段高亮时需设置为 false,表示只要任意一个指定字段匹配查询条件,就对该文档的匹配部分高亮;若为 true,则所有指定字段都必须匹配才会高亮

  • 例:

    • 索引与数据准备。创建 products 索引,指定默认分词器为 ik_max_word,并导入两条产品文档:

      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"
      }
      
    • 默认高亮(匹配字段自动高亮)。查询 name 字段精确为“牛仔”的产品,并对所有字段的匹配内容进行默认高亮:

      GET /products/_search
      {"query": {"term": {"name": {"value": "牛仔"}}},"highlight": {"fields": {"*": {}}}
      }
      
      • 结果中,namedesc 字段中匹配“牛仔”的内容会被 Elasticsearch 默认的高亮标签(如 <em>)包裹;
    • 自定义高亮HTML标签。使用 pre_tagspost_tags 自定义高亮样式(如红色字体),并通过 multi_matchnamedesc 字段查询“牛仔”:

      GET /products/_search
      {"query": {"multi_match": {"fields": ["name","desc"],"query": "牛仔"}},"highlight": {"pre_tags": ["<span style='color:red'>"],"post_tags": ["</span>"],"fields": {"*": {}}}
      }
      
      • 结果中,匹配“牛仔”的内容会被 <span style='color:red'></span> 包裹,呈现红色高亮;
    • 多字段高亮(指定多个字段并控制匹配逻辑)。查询 name 字段精确为“牛仔”的产品,对 namedesc 字段进行高亮,并设置 require_field_match: false(只要任意字段匹配就高亮):

      GET /products/_search
      {"query": {"term": {"name": {"value": "牛仔"}}},"highlight": {"pre_tags": ["<font color='red'>"],"post_tags": ["</font>"],"require_field_match": "false","fields": {"name": {},"desc": {}}}
      }
      
      • 结果中,namedesc 字段中匹配“牛仔”的内容会被红色 font 标签包裹,且只要其中一个字段匹配就会触发高亮。

7 geo_point地理空间位置查询

  • 地理空间位置查询是基于地理位置信息筛选数据的检索方式,广泛应用于地理信息系统(GIS)、位置服务(如旅行、房地产、物流、零售等行业)。在 Elasticsearch 中,它通过地理坐标(经纬度)实现“按距离检索”等空间逻辑;

  • Elasticsearch 中使用 geo_point 字段类型存储地理坐标,该类型可存储纬度(lat经度(lon,用于表示地球上的一个点;

  • geo_distance 查询用于筛选“距离指定坐标点一定范围内”的文档,关键参数包括:

    • distance:最大距离(支持单位如 kmm 等)

    • distance_type:距离计算方式,arc(地球表面弧长,推荐)或 plane(直线距离)

    • location:参考坐标点(包含 latlon

  • 例:

    • 索引与数据准备。创建 tourist_spots 索引,定义 name(文本类型)和 locationgeo_point 类型),并插入多条带地理坐标的景点文档:

      PUT /tourist_spots
      {"mappings": {"properties": {"name": {"type": "text","analyzer": "ik_max_word","search_analyzer": "ik_max_word"},"location": {"type": "geo_point"},"city": {"type": "keyword"}}}
      }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": "杭州"
      }
      
    • 北京附近景点查询(空间查询)。查询“故宫博物院”坐标点 10km 范围内的景点:

      GET /tourist_spots/_search
      {"query": {"bool": {"must": { "match_all": {} },"filter": {"geo_distance": {"distance": "10km","distance_type": "arc","location": { "lat": 39.9159, "lon": 116.3945 }}}}}
      }
      
      • 仅“故宫博物院”会命中(位于自身坐标 10km 范围内);
    • 杭州西湖附近景点查询(空间查询)。查询“西湖”坐标点 5km 范围内的景点:

      GET /tourist_spots/_search
      {"query": {"bool": {"must": { "match_all": {} },"filter": {"geo_distance": {"distance": "5km","distance_type": "arc","location": { "lat": 30.2614, "lon": 120.1479 }}}}}
      }
      
      • “雷峰塔”“苏堤春晓”会命中(均在西湖 5km 范围内)。

8 ElasticSearch 8.x 向量检索

  • Elasticsearch 8.x 引入向量检索(Vector Search)特性,通过 KNN(K-Nearest Neighbors,K-最近邻)算法支持向量近邻检索。其核心思路是将文档(或数据项)表示为高维向量,通过向量相似度计算找到最相似的结果,适用于机器学习、数据分析、推荐系统等领域;

  • 在 Elasticsearch 中,向量数据存储在 dense_vector 类型的字段中,需指定向量的维度(dims

  • KNN 检索的关键参数

    • field:存储向量的字段名(dense_vector 类型)

    • query_vector:用于检索的目标向量

    • k:要返回的最相似文档数量

    • num_candidates:检索时的候选文档数量(用于优化性能)

  • 例:

    • 索引与数据准备。创建 image-index 索引,定义 image-vectordense_vector 类型,维度 3)及其他辅助字段,并批量插入带向量的图像文档:

      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"}
      
    • KNN 向量检索示例。基于目标向量 [-5, 10, -12],检索最相似的 10 个文档:

      POST /image-index/_search
      {"knn": {"field": "image-vector","query_vector": [-5, 10, -12],"k": 10,"num_candidates": 100},"fields": ["title", "file-type"]
      }
      
      • 该查询会通过 KNN 算法计算目标向量与 image-vector 字段中向量的相似度,返回最相似的文档(如“Image A”会因向量高度相似被优先命中)。
http://www.dtcms.com/a/491313.html

相关文章:

  • Spring Boot核心功能深度解析
  • 麒麟系统使用-使用Sublime浏览小说
  • 【2025年10月一区SCI】Experience Exchange Strategy 经验交换策略(EES),优化算法改进新方法!-附Matlab免费代码
  • 渭南建网站如何建立官方网站
  • Azure Cobalt 100 VM:以卓越性能与能效优化云端工作负载
  • 【泛3C篇】AI深度学习在手机背板外观缺陷检测应用方案
  • OpenAI Sora 2 现已在Azure AI Foundry 公共预览中开放
  • 外贸网站推广渠道网站录入
  • **Unreal引擎中的发散创新思维:探索创新与优化之路**随着游戏
  • h5游戏免费下载:电子木鱼
  • h5游戏免费下载:《飞跃的奶酪》
  • 网站速度对seo的影响羽毛球赛事在哪里看
  • 阿里云渠道商:阿里云CDN怎么进行配额优化?
  • 自行车零部件尺寸自动化三维测量快速尺寸测量-中科米堆CASAIM
  • 帮人恶意点击网站岳阳做网站费用
  • 希尔排序解析
  • 水果网站系统的建设与实现人才招聘网站开发背景
  • 订单系统单页面网站怎么做平台制作公司
  • 5种简单方法备份和恢复小米手机
  • 郑州市网站空间服务公司wordpress百度影音
  • FastAPI请求会话context上下文中间件
  • IEEE论文解读 | 基于概念驱动的强化学习探索方法(CDE)
  • 月子会所网站建设方案镇江网络营销外包
  • Windows用户及用户组管理(Server 2019)
  • 云南建站公司江门网站制作服务
  • 使用helm创建属于自己的chart
  • 基于英飞凌MCU实现BLDC无感正弦波FOC控制
  • 《智能体搭建:博查 (Web Search)MCP+Trae 插件调用全流程拆解》
  • 市场体系建设司在官方网站许昌市做网站公司
  • 计算机操作系统文件管理——虚拟文件系统