Elasticsearch Query详解

本文介绍了Elasticsearch中的关键概念,如索引、文档结构、分词与倒排索引,以及查询、过滤、高亮、排序、异步搜索、近实时搜索等特性,详细讲解了如何配置和使用这些功能进行高效的信息检索和管理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

相关概念

  • index,索引,文档的集合,相当于关系型数据库的表(Table),包含表结构(mapping)和表配置(setting)两个选项。
  • mapping,表结构,每个字段的数据类型相关配置。
  • doc,文档,每个文档(Document)相当于关系型数据库中的行(Row),文档的字段(Field)相当于数据库中的列(Column)。
  • Inverted index,倒排索引,先对文档进行分词,词条记录对应文档信息,查询时通过词条定位到文档。
  • analyzer,分词器,将文本拆分成词条,对于英文,可直接按照空格拆分,默认情况下中文会按每个字拆分,支持中文分词需要安装插件。es中分词器的组合包含三个部分
    • character filters,字符过滤器,在分词之前对文本进行处理,例如删除停用词,替换字符等。
    • tokenizer,将文本切分成词条(term)。
    • tokenizer filters,进一步处理分词结果,例如大小写转换,同义词替换等。

filter和query

filter不贡献评分,查询目标是判定是或者否,还可以使用缓存,效率更高。

query计算评分,查询目标是判定相关性,效率比filter低。

index、search和store

  • index,作名词相当于关系型数据库的表;作动词相当于解析文档,创建索引
  • search,搜索阶段
  • store,在ES中有时特指store字段,另存一份;有时是指普通的存储。

store、_source和doc_values

关于三者各自的作用可以查看我的另一篇文章。

我们可以将es对数据的存储查询过程分为三个阶段,索引index,查询search,取回fetch。

index阶段,es解析源文档,按照mapping配置、字段配置对字段进行索引,将整个源文档存储(如果没有禁用_source),将指定的字段进行store,另外存储一份(如果store设置为true),对指定字段建立doc_values存储(如果doc_values可用)。

search阶段,解析query dsl,通过通过索引或者doc_values对字段进行检索和过滤,找到符合条件的文档id,对于需要聚合计算的,取出文档并进行计算?

fetch阶段,按需返回指定的字段,指定_source,fields,或者docvalue_fields,这三个对应三个不同的存储位置,三者存在的作用也不同。

fields、_source、stored_fields、docvalue_fields

这四个都是获取自己想要的字段,通常情况下,es推荐的是使用fields。

fields和_source filter差不多,但是fields会从_source取出相应的字段数据并按照mapping设置进行一些格式处理、运行时字段计算等。

stored_fields是取出被store的字段,通常不建议使用。

docvalue_fields是取出建立了doc_values的字段,部分类型不支持。

检索特性

collapse字段折叠

按照特定的字段分组,每组均返回结果,例如搜索手机,每个品牌都想看看,按品牌字段折叠,返回每个品牌的可排序、过滤的数据。

GET /book/_search
{
  "size": 5,
  "_source": false,
  "query": {
    "match": {
      "info": "化学"
    }
  },
  "collapse": {
    "field": "publish",
    "inner_hits": {
      "_source": {
      	"excludes": {
      		"*vector"
      	}
      },
      "name": "test",
      "size": 2,
      "from": 2
    }
  }
}

filter过滤

有两种使用filter的方式

  • 使用带filter的bool查询,filter会在检索和聚合之前生效。

  • 直接使用post_filter查询,对检索无影响,在聚合之后生效,可以使用rescore提高检索的相关性。

    rescore在所有分片上对query和post_filter的top-k个结果进行算分,可以调整top-k,原score权重,rescore权重,原score和rescore的计算方式(加减乘除平均)。

highlight高亮

对存在检索关键词的结果字段添加特殊标签。es支持三种Highlighter。

  • Unified highlighter,默认的,底层使用Lucene Unified Highlighter,切句分词后BM25评分。
  • Plain highlighter,使用Standard Luncene Highlighter,通过关键字的重要性及关键字的位置信息,尝试尽量的体现查询的匹配逻辑。Plain Highlighter需要针对具体的查询和命中文档的每个字段进行实时的计算,其会在内存中创建一个小型的index,然后通过查询计划重新执行一遍查询,从而获得高亮需要使用底层的匹配信息,所以其比较适合小型的字段。
  • Fast vector highlighter,使用Lucene Fast Vector highlighter,需要设置term_vector为with_position_offsets,会占用更多存储空间,适合多字段、大字段的高亮。不支持span查询。

既然需要高亮指定的句子短语,highlighter需要知道每个词的起始字符位置,有以下几种方式。

  • 索引时分析文本的结果。如果mapping中index_options设置为offsets,unfied highlighter使用这些信息完成高亮而不用再次使用分析器分析文本。它会在预先分析的结果上再次运行查询并从索引中匹配字符偏移。对于大字段来说,不需要重新分析文本是很有意义的,同时相比于term_vector占用更小的磁盘空间。

  • Term vector。如果term_vector参数设置为with_positions_offsets,unified highlighter会自动使用这些信息高亮字段,因为可以直接访问到每个文档的词典,所以能提高大字段(1MB以上)和muti-term查询比如prefix或者wildcard的高亮速度。Fast vector highlighter只能使用term vector。

  • Plain highlighter,当其他highlighter不能用时会使用这个,对于大文本会很耗时间和内存。

    Highlighter是怎么工作的?对于一个查询,highlighter需要找到最佳的文本片段并且高亮目标词句,这里所指的片段是指一个词、多个词或者词句,这必须解决以下三个问题。

    • 如何将文本切片?

      Plain highlighter基于给定的分析器分词,然后遍历每一个词并添加到片段中,当片段将要超过最大fragment_size时,创建新的片段。如果分词不恰当,比如标点符号被单独分出或词以标点符号开头,可能会导致某个片段以标点符号开始。

      Unified或者FVH highlighter使用Java的BreakIterator进行切片,在允许的片段大小下,尽量保证词句的完整性。

      相关的配置选项fragment_size, fragmenter, type, boundary_chars, boundary_max_scan, boundary_scanner, boundary_scanner_locale

    • 如何找到最佳的片段?

      三者都是在给定的查询上对片段进行评分,但是评分计算方式不同。

      Plaing highlighter会在内存中为分词结果重新创建一个索引并执行Lunene的查询并计算得分。片段中每出现一个查询的term,片段的得分加1(boost决定,默认是1),每个片段的每个term只会被计算一次。

      FVH既不需要对文本进行分析,也不需要重新执行查询,而是term_vector的结果,进行切片,按照和Plain highlighter类似的方式计算片段得分,不同的是每个片段的term可以被计算多次。

      Unified highlighter可以使用term_vector或者index_options配置的term_offsets,如果这两者不可用,将会使用Plain highlighter的方式在内存中建立索引并再次进行查询。Unified highlighter使用BM25算法j评分。

    • 如何高亮片段中的词句?

      How to highlight the query terms in a fragment?

async异步搜索

支持异步查询,可使用 get async search查看检索的运行状态。

near real-time近实时搜索

添加或更新文档不修改旧的索引文件,写新文件到缓存,延迟刷盘,可通过API强制更新索引。

pagination分页

普通分页,深度分页scroll,search after。

inner hits不同阶段文档命中

搜索嵌套对象或Join检索、字段折叠等情况下,可以查出具体每个阶段的文档。

例如字段折叠,inner_hits可以查询出折叠每个分组下具体有哪些文档。

支持name、sort、from、size参数。

selected field返回需要的字段

使用_source filter、fileds、docvalue_fields、stored_fields返回需要的文档字段。

across clusters分布式检索

支持多种检索API的分布式搜索。

multiple indices多索引检索

支持同时从一次从多个索引检索数据。

shard routing分片路由

ES将索引分片并可以重复保存在多个节点上,可以提高容错和检索能力。默认情况下ES自动根据负载情况、响应时间选择合适的节点查询。在查询中可以配置preference优先去哪个节点查询,可以配置routing指定分片查询,可以配置每个节点同时并发检索的分片数。

自定义检索模板search templates

复用的检索模板,根据不同变量生成不同query dsl,Mustache语法。

同义词检索search with synonyms

定义同义词集,在索引和检索阶段可以被文本分析器中的tokenfilter使用,提高检索准确度。ES中提供了三种方法配置同义词

  • 使用synonyms APIs,可以动态灵活的定义和修改同义词集。使用这种方法修改同义词集后文本分析器会被自动重新加载,使用这种方法同义词替换只能用在搜索阶段。
  • 使用文件方式,在每个节点上(相对于ES配置目录)放置同义词文件,在每个节点上更新文件后,需要手动调用reload search analyzers API
  • 直接在tokenfiler定义时指定,不推荐。

以下是同义词文件示例

# 左边的词在tokenfilter会被替换为右边的词
i-pod, i pod => ipod
sea biscuit, sea biscit => seabiscuit

# 取决于同义词的expand配置
ipod, i-pod, i pod
foozball , foosball
universe , cosmos
lol, laughing out loud

# expand为true的情况(默认),左边任意一个词会被替换为右边三个词
ipod, i-pod, i pod => ipod, i-pod, i pod
# expand为false,相当于左边任意三个词替换为右边一个词
ipod, i-pod, i pod => ipod

# 以下两行配置
foo => foo bar
foo => baz
# 相当于下面一行配置
foo => foo bar, baz

何时使用同义词替换

  • 索引阶段,也就是说分词之后tokenfilter进行同义词替换,然后建立索引,如果同义词更新,需要重建索引。

  • 搜索阶段,同义词替换只发生在搜索阶段,同义词库文件变化不需要重建索引。

    通过配置analyzer和search_analyzer指定何时使用同义词替换。

排序sort results

支持多字段,数组字段、嵌套字段排序,对于数组的排序,可以选择数组的最大值、最小值、平均值等作为排序依据。对一个字段指定排序后,不再计算评分,除非指定track_score。

  • 最邻近搜索knn search,检索最邻近的向量,常用于相关性排名、搜索建议、图像视频检索。

  • 语义检索semantic search,按语义和意图检索,而不是词汇检索,基于NLP和向量检索,支持上传模型,在存储和检索时自动编码,支持混合检索。

    所有的检索特性可以查看官方文档

查询

query和filter

query用于回答相似度是多少的问题,计算评分。

filter用于回答是或否的问题,不计算评分,可使用缓存,效率更高

组合查询

Boolean
Boosting
  • match,最常用,分词,全文检索。

  • match_phrase,与match类似,但是索引分词和查询分词结果必须相同,包括分词得到的顺序,可配置参数slop,允许词和词之间出现其他token的数量。

    本人在ik分词测试,需要将analyzer和search_quote_analyzer设置成一样的分词器,才能正确检索出结果。

    match_phrase容易受到停用的影响,不配置ik的停用词影响match搜索,配置之后影响match_phrase,本人使用ik的tokenizer自定义analyzer,但是
    ik的tokenizer就完成了中文标点去除、停用词去除以及分词的功能,无法配置其仅完成分词,需要修改源码。

<think>好的,用户让我详细介绍一下Elasticsearch中的query_string查询。首先,我需要回忆一下自己对query_string的理解,确保知识点准确。记得query_string是一个比较强大但也复杂的查询方式,允许用户使用Lucene的查询语法,可能用户在使用过程中遇到了一些问题,或者想更深入理解它的用法和注意事项。 首先,我应该从基本概念入手,解释什么是query_string查询,它的作用是什么。然后需要分点说明它的核心特性,比如支持哪些操作符,通配符,模糊查询等等。这部分需要结构清晰,用用户容易理解的语言描述,避免太技术化的术语。 接下来,用户可能需要知道语法结构,所以给出一个基本的示例,比如字段指定、多字段查询等。同时,要提到默认字段的设置,以及如何组合多个条件。这部分要注意代码示例的正确性,使用中文注释可能更友好。 然后,要讨论它的高级功能,比如布尔逻辑、范围查询、模糊匹配、通配符等。每个功能点都需要简要说明,并给出例子。例如,通配符的使用和性能问题,模糊查询的波浪号用法,这些都是用户容易出错的地方,需要强调注意事项。 之后,必须提到它的优缺点。优点方面,灵活性和Lucene语法的支持是重点。缺点方面,比如语法严格、安全性问题(SQL注入类似的攻击),以及性能问题,这些对用户的实际应用很重要,特别是生产环境中需要注意的地方。 最后,给出一个总结,建议用户在不同场景下的使用,比如调试时可以用query_string,但生产环境更推荐其他更安全的查询方式。可能用户在使用时遇到了语法错误或者性能问题,所以这些注意事项对他们来说非常关键。 在组织内容的时候,要确保各部分之间有逻辑衔接,避免重复。同时,检查是否有遗漏的重要点,比如默认操作符OR和AND的区别,转义特殊字符的方法,这些都是用户常见的问题点。另外,要提醒用户关于字段是否存在的情况,wildcard字段查询可能带来的性能影响,这些实际开发中的经验对用户很有帮助。 最后,确保整个回答符合之前设定的格式要求,使用中文,行内公式正确,独立公式单独成段,但在这个问题中可能用不上数学公式,所以主要注意代码块和结构。检查LaTeX语法是否正确,虽然这个问题可能不涉及太多公式,但如果有需要的地方要正确使用。 总结一下,回答的结构应该是:概述、核心特性、语法结构、高级功能、优缺点、使用场景与注意事项。确保每个部分简明扼要,举例恰当,同时警告常见陷阱,帮助用户正确有效地使用query_string查询。</think>Elasticsearch 的 `query_string` 查询是一种**灵活但语法复杂**的查询方式,它允许直接使用 **Lucene 查询语法**进行搜索。以下是其核心特性与使用详解: --- ### 一、核心特性 1. **支持丰富语法** - 支持 `AND`/`OR`/`NOT` 布尔逻辑 - 支持通配符 (`*` 匹配多个字符, `?` 匹配单个字符) - 支持模糊搜索 (`~`,如 `roam~` 匹配 "roam" 或 "foam") - 支持范围查询 (`[min TO max]`,如 `price:[100 TO 200]`) - 支持正则表达式 (`/pattern/`,如 `/[ta]o?y/` 匹配 "toy" 或 "roy") 2. **多字段查询** 可一次性搜索多个字段(需显式指定或通过 `default_field` 配置): ```json { "query": { "query_string": { "query": "title:(quick brown) OR content:fox", "default_field": "title" // 默认字段(可选) } } } ``` 3. **默认操作符** 未指定时,默认使用 `OR` 逻辑(可通过 `default_operator` 修改为 `AND`)。 --- ### 二、语法示例 #### 1. 基础查询 ```json { "query": { "query_string": { "query": "(apple AND orange) OR banana", "fields": ["title", "description"] // 指定搜索字段 } } } ``` #### 2. 通配符与模糊匹配 ```json { "query": { "query_string": { "query": "qu?ck~2", // 匹配 "quick"(允许两个字符差异) "fields": ["text"] } } } ``` #### 3. 范围与正则 ```json { "query": { "query_string": { "query": "price:[100 TO 200] AND /error[0-9]{3}/", "default_field": "log" } } } ``` --- ### 三、高级功能 1. **权重提升 (`^`)** 通过 `^` 指定字段权重: ```json "query": "title:apple^2 OR content:apple" ``` 2. **短语搜索 (`"..."`)** 精确匹配短语: ```json "query": "\"quick brown fox\"" ``` 3. **转义特殊字符** 对 `+ - = && || > < ! ( ) { } [ ] ^ " ~ * ? : \ /` 等字符需用 `\` 转义。 ```json "query": "http\\:\\/\\/example.com" ``` --- ### 四、优缺点分析 | **优点** | **缺点** | |-----------------------------|-----------------------------| | 1. 灵活,支持复杂查询逻辑 | 1. 语法严格,错误易导致查询失败 | | 2. 直接复用 Lucene 语法 | 2. 安全性风险(需防范注入攻击) | | 3. 适合调试和快速搜索 | 3. 性能较差(复杂查询需更多资源) | --- ### 五、注意事项 1. **避免生产环境滥用** 推荐优先使用更安全的 `match` 或 `term` 查询。 2. **防范注入攻击** 用户输入需严格过滤(如禁止 `*` 或 `?` 等通配符)。 3. **性能优化** - 避免在 `text` 字段使用通配符开头的查询(如 `*apple`) - 限制范围查询和正则表达式的复杂度 --- ### 总结 `query_string` 适合**快速原型设计或复杂查询需求**,但需谨慎处理语法细节与安全性。对于简单场景,建议优先使用 `match`、`term` 或 `bool` 查询。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值