为什么lucene/elasticsearch前缀查询比术语查询慢?

cs7cruho  于 2021-06-13  发布在  ElasticSearch
关注(0)|答案(1)|浏览(470)

我最近读到了关于lucene和elasticsearch的文章,似乎以下是真的(如果我错了,请纠正我):
前缀查询比术语查询慢
后缀查询(ing)比前缀查询(ing)慢
这似乎是一个奇怪的属性组合。也许我需要扩大我正在考虑的数据结构的范围,但是如果一个段的结构像一个哈希表,我可以很容易地看到1是真的(术语查询是o(1),前缀查询需要完全扫描),但是2不是真的(前缀和后缀都需要完全扫描)。如果段像排序数组一样排列,我可以很容易地看到2是真的(前缀查询可以用二进制搜索o(logn)执行,后缀需要完全扫描),但是1不再是真的(术语和前缀查询都需要二进制搜索)。
我唯一的另一个想法是,可能会有一些哈希和排序的组合来解释这种行为(例如,哈希到某个分区和该分区内的排序)。然而,我的理解是,elasticsearch通过文档标识符进行分区,而反向索引键是一个术语。因此,对术语的查询仍然需要将请求发送到所有分区。
有没有人能给我一些关于这种行为是如何/为什么存在的直觉?
注:
https://www.youtube.com/watch?v=t5rmmndr5xi 这意味着段的结构类似于排序数组,而不是哈希表。
我相信1是真的原因是https://medium.com/@mourjo_sen/a-detailed-comparison-between-autocompletion-strategies-in-elasticsearch-66cb9e9c62c4提到“在生产环境中不应该使用前缀查询的最重要原因是它们非常慢。原因是es中的令牌不能直接作为前缀”
我相信2是真的原因是https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-query-string-query.html 提到“允许在单词的开头使用通配符(例如“*ing”)特别重要,因为索引中的所有术语都需要检查,以防它们匹配

uemypmqf

uemypmqf1#

我不太熟悉es的具体细节,所以他们可能会做一些其他的事情,而不是简单的解决方案-但是#1通常不是这样。
前缀匹配将比查找单个术语更昂贵,但也没有那么贵。它可以与范围搜索(如果您想- field:[aa TO ab) 可以比作 field:aa* (理论上);有效地检索该范围内的所有标记,然后解析与这些标记匹配的文档集。
有更多匹配的标记这一事实意味着您不能简单地获取附加到单个标记(匹配项)的列表并检索那些文档,但是您必须检索一组可能很大的匹配标记,然后计算文档集。然而,这不是一个非常昂贵的计算,但它比仅仅一个匹配更昂贵。查找可以通过在索引中找到匹配标记的起始索引和结束索引来完成,然后检索这两个标记之间的所有项并找到匹配的文档id集。
对…的质疑 foo* 针对具有以下术语的索引:

bar, baz, foo, foobar, spam
          ^----------^

将收集所附文件的列表 foo 以及 foobar ,合并它,然后检索文档。
慢并不意味着它是灾难性的或没有以任何方式优化;只是它比直接匹配的文档集已经确定要贵。但是,您的查询中可能已经有多个术语了,因此同样的过程(尽管在层次结构中略高一点)也会在那里发生。
后缀匹配(您的#2)-即匹配令牌开头的通配符-代价很高,因为通常必须考虑索引中的所有令牌。索引中的术语按字母数字排序,因此当您只想查看字符串的结尾时,必须考虑每个标记都可以匹配,而不管它在索引中的位置如何-这样您就可以得到完整的索引扫描。但是,如果这是一个经常发生的用例,那么可以使用反向通配符过滤器。它的工作原理是反转字符串并使标记以相反的顺序与术语匹配,以便 foo 索引为 oof 通配符搜索变成了 oof* 相反。
对…的质疑 *ar 针对具有以下术语的索引:

bar, baz, foo, foobar, spam
?!   ?    ?    ?!      ?

将不得不看每一个学期,以决定它是否以 ar .
使用edgengramfilter(您的注解/#3)的原因是,您将尽可能多的所需处理移到索引时间(做您知道的工作是查询时间,即使前缀查询不是非常昂贵,它们仍然有成本),此外:通配符查询不支持大多数分析。因此,许多人最终会对一组已生成词干或以其他方式处理的标记进行通配符查询,当他们的通配符查询没有生成匹配项时,他们会感到惊讶。只有一小部分筛选器可以应用于通配符查询(例如小写筛选器)。这些过滤器被称为“多术语感知”,因为过程中的术语最终可能会在文档集合发生之前扩展为多个术语。
另一个原因是使用edgengramfilter可以为每个前缀提供适当的频率分数,也可以为前缀项提供有效的分数。

相关问题