Elasticsearch:过滤器顺序以获得最佳性能

时间:2016-01-11 17:07:12

标签: performance elasticsearch

Elasticsearch指南说

  

“每个过滤器都是独立计算和缓存的,无论它在何处使用。如果两个不同的查询使用相同的过滤器,则将重用相同的过滤器位集。同样,如果单个查询在多个位置使用相同的过滤器,只计算一个bitset,然后重复使用。“   (https://www.elastic.co/guide/en/elasticsearch/guide/current/filter-caching.html

在另一页上也说:

  

“bool子句中的过滤器顺序对于性能很重要。应该在不太具体的过滤器之前放置更具体的过滤器,以尽可能早地排除尽可能多的文档。如果条款A可以匹配10百万份文件,条款B只能匹配100份文件,然后条款B应放在条款A之前。“   (https://www.elastic.co/guide/en/elasticsearch/guide/current/_filter_order.html

我不太明白当每个过滤器独立缓存时,bool子句中过滤器的顺序是如何重要的。

我认为从缓存中执行或检索子句B,从缓存执行或检索子句A,然后过滤器位集“合并”。为什么订单很重要?

4 个答案:

答案 0 :(得分:14)

这个指导有点误导。它更复杂,很难尝试编写适合所有情况的一套规则。随着数据的变化,规则会发生变化。随着查询和过滤器类型的更改,规则会发生变化。执行的特定过滤器可能比宽泛的过滤器更慢,规则会发生变化。在每个段的基础上,过滤器的结果大小可能与另一个段的结果大小相反,它并不总是可预测的。 首先,您必须了解更多内部,然后在进入现代Elasticsearch 2.x时需要放弃尝试控制它。

注意: 您的第二个引用(过滤顺序)和关联的链接指向被视为"过时的页面"对于Elasticsearch 2.x,它将在以后更新。因此,这些建议可能适用于现代,也可能不适用。

回顾Elasticsearch 1.x以及订购建议的原因:

让我们首先谈谈过滤器如何在内存中表示。它们或者是匹配文档的迭代列表,或者是随机访问"它在这里"模型。根据过滤器的类型,取决于哪个更有效。现在,如果所有内容都被缓存,那么您只是将它们相交,成本会因尺寸和类型而异。

如果过滤器没有缓存,但可以缓存,那么过滤器将独立执行,之前的过滤器只会影响交叉总成本。

如果过滤器不可缓存,那么它可以由之前的结果引导。想象一下Query加上Filter。如果执行查询,并且在应用过滤器之后,如果过滤器限制为非常小的记录集,则会执行大量额外工作。您在查询中浪费了时间,收集,评分和整体构建了大量结果。但是,如果您转换为FilteredQuery并同时执行这两项操作,则Query会忽略Filter已消除的所有记录。它只需要考虑已经在使用的相同文档。这被称为"跳过"。并非所有过滤器类型都利用跳过,但有些可以。这就是为什么一个较小的"指导"过滤器会让其他人更快地使用它。

除非您了解每种过滤器类型,数据的启发式以及每种特定过滤器将如何受其影响,否则您只是没有足够的信息而不是说"放置最多限制首先过滤,然后过大的过滤" 并希望它能够解决问题。对于bool,默认情况下不会缓存其整体结果,因此您必须注意其重复性能(和/或缓存它)。当滤波器交叉点的一侧很小时,它更有效。所以有一个小的开始使所有其他交叉点更快,因为它们只能变小。如果是bool 查询而不是过滤器进行评分,则避免对必要的文档进行评分更为重要。

另一个重要的注意事项是"最具体的过滤器#34; 有时可能很慢(脚本过滤器或其他),所以它应该真正读取:&# 34;最低成本,最具体的过滤器首先"

使用Elasticsearch 2.0, things will change

  

现在是时候忘记了解查询和过滤器的所有内容:Elasticsearch 2.0本身可以做出更好的决策,而不是依靠用户来制定优化的查询。

在2.x中你应该少尝试游戏系统,让引擎做出最好的选择。发动机实际上可能会在引擎盖下有一些完全不同的东西,一个重写的过滤器,内部结构和数据的完全变化。你甚至可能不再控制缓存了。所以你需要阅读更多相关信息。

  

以前的过滤器API可以通过两种方式使用:使用迭代器而不是匹配文档,或者使用可选的随机访问API,以便检查特定文档是否与过滤器匹配。到目前为止,一切都很好,除了使用过滤器的最佳方式取决于您使用的过滤器类型:例如script过滤器在使用随机访问API时效率更高bool使用迭代器API,filter更有效。这是优化的噩梦,也是导致bool过滤器和另一方面andor过滤器执行不同的原因的根本原因。

引擎现在将决定考虑更多因素的最佳因素,包括评分,结果大小估计,相关过滤器交叉的最佳方式,甚至可能基于每个细分,等等。

此外文章也清楚地表明,即使缓存可能会产生误导,但它并不能让事情变得更快。有时内部数据结构在最初使用时比总是缓存的bitset结构更好。因此,在2.x中,这也是为了避免缓存从本机数据结构中执行得更好而没有缓存的事情。

在博客文章Roaring Bitmaps中有更多详情:

  

显然,最重要的要求是快速拥有一些东西:如果你的缓存过滤器比再次执行过滤器慢,它不仅消耗内存而且还使你的查询变慢。编码越复杂,由于CPU使用率的增加,越有可能减慢编码和解码速度

在这里,您可以获得有关内部数据结构,缓存,交集以及2.x内部更改的更多信息,这将有助于您更深入地了解过滤器性能。

  

如果您不熟悉搜索引擎内部构件,可能会让您大吃一惊,搜索引擎最重要的构建模块之一就是能够有效地压缩和快速解码排序的整数列表。

从最后几个2.x博客链接中,您有很多关于您的问题的背景信息,他们会讨论您尝试使用过滤器排序的所有问题。信息和详细信息都在那里,您可以更好地理解1.x与2.x以及如何解决查询+过滤器。所以请记住:

  

没有特别的实施方式总是比其他实施方式更好。

另请参阅这些1.x资源以获取历史参考:

  • Optimizing Elasticsearch searches涵盖了有关过滤器排序的更多内容。它总结说:

      

    尽管如此,您仍然需要考虑过滤哪个订单。您希望首先运行更具选择性的过滤器。假设您按类型过滤:book和tag:elasticsearch。如果您有3000万个文档,1000万个类型书,只有10个标记的Elasticsearch,那么您首先要应用标记过滤器。它比书籍过滤器减少了更多的文档数量。

  • All About Elasticsearch Filter Bitsets被认为是现代的过时文章,但它提供了有关您引用的过滤器订购文档的更多背景信息。

  • A forum answer by Martijn v Groningen似乎反对booland查询有关哪些使用迭代与随机访问,但每个人的想法是相同的:安全通过限制过滤器列表中较早的文档 - 无论哪种类型的模型与另一种类型相比。

答案 1 :(得分:3)

并非所有过滤器都是缓存/可缓存的。例如,使用range变量的日期范围过滤器不会被缓存,因为它会一直更改。如果你在你提供的第一个链接中看得更远,你会看到一个名为"Controlling caching"的部分,其中说明了这一事实:

  

默认情况下,某些叶子过滤器不会被缓存,因为这样做没有意义:脚本过滤器,地理过滤器,日期范围过滤器。

为了说明这一点,我们假设我们有以下日期"range" : { "timestamp" : { "gt" : "now-1m" } } 过滤器(让我们称之为过滤器A)过滤掉过去一个月的所有文件

term

和另一个XYZ过滤器(让我们称之为过滤器B)来过滤类型为"term" : { "type" : "XYZ" } 的文档

type

如果你放置

,它会产生很大的不同(表现明智)
  1. 过滤器B之前的过滤器A或
  2. 过滤器A之前的过滤器B
  3. 在案例1中,执行速度会变慢,因为过去一个月的所有文档都需要首先通过过滤器A,而不是高速缓存。

    在案例2中,您首先过滤掉所有没有XYZ {{1}}的文档,这很快,因为过滤器B已缓存。然后,通过过滤器B的文档可以通过过滤器A.因此,即使过滤器A没有被缓存,执行仍然会更快,因为过滤器管道中剩余的文档较少。

    这是一个非常简单的例子,但它应该说明为什么过滤器顺序很重要,即主要是因为某些过滤器没有被缓存。您可以通过强制缓存来更改默认行为,但有时这不是一个好主意。最佳做法是首先应用最具侵略性的过滤器,以便让尽可能少的文档通过下一个过滤器。

    我个人称之为"推土机方法",即首先确保尽可能早地在过滤器管道中处理尽可能多的材料,并最终得到更可咀嚼的数据块可以更快地处理。

答案 2 :(得分:2)

2017年5月发布的blog post on elastic website表示

  

问:我将查询/过滤器放入查询DSL的顺序   物?

     <答>答:不,因为无论如何它们都会自动重新排序   根据各自的成本和匹配成本。

答案 3 :(得分:-1)

我认为将较小的一组匹配文档合并到较大的集合中效率更高,或者按此顺序操作可以提高零匹配的可能性,从而可以采取快捷方式。需要检查源代码(ElasticsearchLucene)才能确定。

如果我错了,请纠正我......