为什么需要过滤器聚合?

时间:2017-04-11 11:01:03

标签: elasticsearch elasticsearch-5

在使用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子句,我们就不会遇到问题,对于过滤器而不是查询也是如此。这对我们来说是最令人惊讶的,因为应该只有一个桶,任何排序都是微不足道的。这使我相信在分组之前没有进行过滤,因此我尝试将所有内容都包含在过滤聚合中。

2 个答案:

答案 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)

如果您有嵌套文档,则还需要过滤聚合。这允许在特定子文档上聚合而不是在所有项目上聚合。

相关问题