在使用elasticsearch(5.3.0)时,我们遇到了涉及一些嵌套聚合的查询的内存不足问题。
我们在经验上发现问题是聚合是在完整索引上计算的,而不是考虑query
块中指定的条件。我们之后设法运行查询将这些条件移动到filter
聚合(请参阅docs),其中包含了所有原始aggs。
为什么有单独的语法?如果elasticsearch在填充存储桶时只考虑所有查询条件,那会不会更好?
如果我选择以这种方式将所有聚合查询包装在filter
查询中,有什么风险和/或限制?逻辑有什么不同吗?
注意:在我们的应用程序中,我们根本不关心文档评分。所有条件的唯一目的是过滤文档,而不是对文档进行排序。我们会根据文档计数或聚合指标过滤存储桶。
编辑:有些人要求查询,在这里他们会帮助澄清情况。请注意,此问题是一般性的,并且不特定于此特定情况。
{
"query": {
// we did try a filtering rather than a query with the same results
"term": {
"urlpath": "some_url_path.html"
}
},
"aggs": {
"agg_1": {
"terms": {
"size": 10,
"order": {
"sessions_number": "desc"
},
"field": "urlpath"
},
"aggs": {
"sessions_number": {
"cardinality": {
"field": "session"
}
}
}
}
}
}
之后:
{
"aggs": {
"agg_0": {
"filter": {
"term": {
"urlpath": "some_url_path.html"
}
},
"aggs": {
"agg_1": {
"terms": {
"size": 10,
"order": {
"sessions_number": "desc"
},
"field": "urlpath"
},
"aggs": {
"sessions_number": {
"cardinality": {
"field": "session"
}
}
}
}
}
}
}
}
EDIT2:我尝试使用过滤查询,如下面的@Lusid所示,但遇到了同样的问题。
注意2:如果我们删除order
子句,我们就不会遇到问题,对于过滤器而不是查询也是如此。这对我们来说是最令人惊讶的,因为应该只有一个桶,任何排序都是微不足道的。这使我相信在分组之前没有进行过滤,因此我尝试将所有内容都包含在过滤聚合中。
答案 0 :(得分:0)
在您的第一个示例中,您实际上并非过滤数据,而是查询数据。这只会影响搜索结果的评分过程,而不会影响聚合过滤。
尽管最新版本的ElasticSearch结合了查询/过滤器语法,但理解两者之间的区别仍然很重要。根据此处的文档:https://www.elastic.co/guide/en/elasticsearch/reference/current/query-filter-context.html
查询上下文中使用的查询子句回答了问题“如何 这个文档是否符合这个查询条款?“除了决定是否 或者文档是否匹配,查询子句还计算_score 表示文档相对于其他文档的匹配程度 文档。
在过滤器上下文中,查询子句回答问题“这是否 文档匹配此查询子句?“答案是简单的是或 否 - 没有计算得分。过滤器上下文主要用于 过滤结构化数据,例如
构建第一个查询的更好方法是将过滤器包装在 query.bool 或 query.constant_score 中,如下所示:
{
"query": {
"bool": {
"filter": {
"term": {
"urlpath": "some_url_path.html"
}
}
}
},
"aggs": {
"agg_1": {
"terms": {
"size": 10,
"order": {
"sessions_number": "desc"
},
"field": "urlpath"
},
"aggs": {
"sessions_number": {
"cardinality": {
"field": "session"
}
}
}
}
}
}
有关这两个选项的更多信息:
常量分数查询: https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-constant-score-query.html
Bool查询(过滤部分): https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-bool-query.html
当然,拥有这两个选项的好处是您可以为整个搜索应用整体过滤器,但随后会进一步过滤聚合。
希望这有帮助!
编辑:由于在查询中使用过滤器,因此我主要解决过滤器背后的原因不能按照您期望的方式运行。至于记忆问题,你确定你不会在这里引发组合爆炸吗?您可以尝试将bread_mode的breadth_first添加到顶级聚合中吗?有关组合爆炸的更多信息,请访问:https://www.elastic.co/guide/en/elasticsearch/guide/current/_preventing_combinatorial_explosions.html
试试这个:
{
"query": {
"bool": {
"filter": {
"term": {
"urlpath": "some_url_path.html"
}
}
}
},
"aggs": {
"agg_1": {
"terms": {
"size": 10,
"order": {
"sessions_number": "desc"
},
"field": "urlpath",
"collect_mode": "breadth_first"
},
"aggs": {
"sessions_number": {
"cardinality": {
"field": "session"
}
}
}
}
}
}
答案 1 :(得分:0)
如果您有嵌套文档,则还需要过滤聚合。这允许在特定子文档上聚合而不是在所有项目上聚合。