为什么ES中不推荐使用wildcard查询

lucene中AutomatonQuery类的作用中,我们说了 AutomatonQuery 性能很高。

那么,为什么 Elasticsearch 的官方文档和所有最佳实践都强烈建议不要使用前缀通配符(leading wildcard) ,比如 *text

答案在于 AutomatonQuery 的高效是有条件的,而前缀通配符恰好破坏了这个条件。


核心原因:与有序词项词典(Term Dictionary)的交互方式

Lucene 的性能秘诀在于它的倒排索引,其中一个关键部分是词项词典(Term Dictionary) 。这个词典存储了索引中所有唯一的词项,并且是按字典序(alphabetically)排序的

这个"按字典序排序"的特性至关重要。我们来对比两种通配符查询:

1. 后缀通配符查询(Trailing Wildcard)- 性能很高 (text*)

当你执行一个像 text* 这样的查询时:

  1. 构建自动机 :Lucene 构建一个自动机,它匹配以 text 开头的任何字符串。
  2. 遍历词典 :由于词典是按字典序排序的,所有以 text 开头的词项(如 textbook, testing, texture)都连续地存放在一起
  3. 高效查找 :Lucene 的查询执行器可以非常高效地:
    • **直接定位(Seek)**到词典中第一个以 text 开头的词项。这就像在字典里查 "text" 这个单词一样快。
    • 然后,它只需要顺序扫描 该位置之后的少量词项,直到遇到第一个不以 text 开头的词项为止。
    • 整个过程非常快,因为它只需要检查词典中一个很小的、连续的片段。

这正是 AutomatonQuery 高性能的典型场景。

2. 前缀通配符查询(Leading Wildcard)- 性能灾难 (*text)

当你执行一个像 *text 这样的查询时:

  1. 构建自动机 :Lucene 构建一个自动机,它匹配以 text 结尾的任何字符串。
  2. 遍历词典 :问题来了。因为词典是按开头 字母排序的,所以以 text 结尾的词项(如 context, subtext, hypertext)会分散在整个词典的各个角落
  3. 低效查找 :为了找到所有匹配项,AutomatonQuery 别无选择,只能:
    • 从词典的第一个词项(比如 "a")开始。
    • 逐个检查词典中的每一个词项 ,看它是否以 text 结尾。
    • 这个过程会一直持续到词典的最后一个词项

这相当于对整个字段的词项词典进行了一次全量扫描(Full Scan)

这为什么在 Elasticsearch 中是灾难性的?

  • 规模放大:一个 Lucene 索引(在 ES 中称为分片/Shard)的词项词典可能包含数百万甚至数千万个唯一词项。对单个分片进行全量扫描已经非常耗费 CPU。
  • 分布式特性 :一个 Elasticsearch 索引通常由多个分片组成,这些分片分布在集群的多个节点上。当你执行一个 *text 查询时,这个全量扫描的操作会在所有相关的分片上并行执行
  • 集群影响 :这个查询会瞬间占用大量 CPU 资源,导致集群的查询延迟飙升,影响所有其他正在进行的查询,甚至可能因为负载过高而导致节点不稳定。它被称为"Query of Death"(死亡查询)之一。

总结:理论与实践的鸿沟

  • 理论上AutomatonQuery 本身是一个高效的算法。
  • 实践中 :它的性能高度依赖于它所操作的数据结构。当与一个有序 的词典结合使用时,对于前缀友好 的模式(如 text*),它可以利用"有序"这一特性进行快速定位,性能极高。但对于前缀不友好 的模式(如 *text),它无法利用"有序"特性,被迫退化为全量扫描,性能极差。

Elasticsearch 作为一个大规模、多租户的系统,必须优先保证整个集群的稳定性和性能。因此,它强烈建议避免那些会导致资源浩劫的操作,而前缀通配符查询正是其中的典型代表。


那么,如何解决需要匹配"中间"或"结尾"的需求?

既然直接用 *text 不行,Elasticsearch 社区发展出了一些标准的解决方案,核心思想是在索引时做一些额外的工作,将慢查询转换为快查询

  1. reverse Token Filter(反转词元过滤器)

    这是解决前缀通配符最经典的方法。

    • 索引时 :对原始词项(如 context)建立一个反转后的版本(txetnoc)并存入另一个子字段。
    • 查询时 :当用户想搜 *text 时,你将查询条件反转为 txet*,然后去查询那个反转后的字段。
    • 效果 :一个慢速的、全量扫描的前缀通配符查询 ,变成了一个高速的、可以快速定位的后缀通配符查询
  2. n-gram Token Filter(N元分词过滤器)

    • 索引时 :将一个词项(如 text)拆分成一系列的小片段(n-grams)。例如,2-grams 会拆成 te, ex, xt;3-grams 会拆成 tex, ext
    • 查询时 :当用户搜索 *text**tex* 时,可以被转换为对 tex 这个 n-gram 的精确匹配查询,速度非常快。
    • 缺点:会极大地增加索引的体积。

AutomatonQuery 本身是把好刀,但用它来砍一个四处分散的目标(前缀通配符),就只能把整个场地犁一遍了。而用它来砍一个整齐排列的目标(后缀通配符),则快如闪电。Elasticsearch 的建议正是基于这种实际应用场景的深刻理解。

相关推荐
19岁开始学习3 小时前
PHP操作elasticsearch7.8
elasticsearch·jenkins·php
Elasticsearch4 小时前
Simple MCP Client - 连接到 Elasticsearch MCP 并进行自然语言搜索
elasticsearch
罗技1239 小时前
Elasticsearch、OpenSearch 与 Easysearch:三代搜索引擎的演化与抉择
大数据·elasticsearch·搜索引擎
极限实验室18 小时前
Elasticsearch 备份:snapshot 镜像使用篇
数据库·elasticsearch
gb42152871 天前
elasticsearch索引多长时间刷新一次(智能刷新索引根据数据条数去更新)
大数据·elasticsearch·jenkins
熊文豪1 天前
Windows安装Elasticsearch保姆级教程
大数据·windows·elasticsearch·kibana
INFINI Labs2 天前
Elasticsearch 备份:方案篇
大数据·elasticsearch·搜索引擎·gateway·snapshot·backup·ccr
NickBi2 天前
龙芯 LoongArch64编译es7.17.20
后端·elasticsearch
渣渣盟2 天前
中文分词技术全解析
搜索引擎·全文检索·lucene