【问题标题】:Why is the filter aggregation necessary?为什么需要过滤聚合?
【发布时间】:2017-04-11 11:01:02
【问题描述】:

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

【问题讨论】:

  • 您能发布您的初始查询和修改后的查询吗?

标签: elasticsearch elasticsearch-5


【解决方案1】:

在您的第一个示例中,您实际上并没有过滤数据,而是查询数据。这只会影响搜索结果的评分过程,不会影响聚合过滤。

即使最新版本的 ElasticSearch 结合了查询/过滤器语法,了解两者之间的区别仍然很重要。根据这里的文档:https://www.elastic.co/guide/en/elasticsearch/reference/current/query-filter-context.html

查询上下文中使用的查询子句回答了“How well 该文档与该查询子句匹配吗?”除了决定是否 与文档不匹配,查询子句也会计算一个 _score 表示文档相对于其他文档的匹配程度 文件。

在过滤器上下文中,查询子句回答“这样做 文档匹配这个查询子句?”答案很简单,是或 否 — 不计算分数。过滤上下文主要用于 过滤结构化数据,例如

构建第一个查询的更好方法是将过滤器包装在 query.boolquery.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

布尔查询(过滤部分): https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-bool-query.html

当然,同时使用这两个选项的好处是您可以为整个搜索应用一个整体过滤器,然后进一步过滤聚合。

希望这会有所帮助!

编辑:我主要是解决过滤器背后的原因,原因是由于在查询中使用它,过滤器无法按照您在聚合中所期望的方式运行。至于内存问题,你确定这里没有触发组合爆炸吗?您可以尝试将宽度优先的 collect_mode 添加到顶级聚合中吗?更多关于组合爆炸的信息: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"
          }
        }
      }
    }
  }
}

【讨论】:

  • 感谢您的回答;我立即尝试了您的变体,但不幸的是我得到了相同的结果(内存不足)。我很快会在问题中添加更多细节作为编辑。
  • 你说得对,我没有解决内存问题。我已经更新了我的答案,以提出内存问题的可能原因和解决方案(虽然,没有看到你的数据,我不能确定)。
【解决方案2】:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-01-27
    • 1970-01-01
    • 2015-11-25
    • 2021-11-23
    • 2014-04-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多