【问题标题】:Elasticsearch - sub aggregation with a large amount of bucketsElasticsearch - 具有大量存储桶的子聚合
【发布时间】:2021-04-02 22:02:57
【问题描述】:

我们有一个包含大量用户报告的索引(数百万 / 数千万)。 假设大多数用户都有报告,我们需要计算每个用户的一些统计数据。 例如,有多少用户在特定时间间隔内每周平均有 10-15、15-20、20-30 份报告。 请注意,我们不需要在响应中返回存储桶本身,但它们需要由计算平均值和范围的子聚合进行评估。据我了解,elasticsearch对bucket的数量是有限制的,不建议增加到百万。 我已经阅读了关于分页的复合聚合,但我认为这不适合这种情况,因为我们需要计算聚合数而不是返回存储桶。

以下是我们当前查询的简化版本。 我们想要计算两个日期之间 X1-X2 月度报告的使用次数。

  1. 按用户 ID 存储报告。
  2. 使用存储桶选择器仅选择具有 YZ 报告之间的用户(Y1 和 Y2 由客户预先计算 - 这些数字将解析为 X1-X2 月报告之间的平均值)。
  3. 计算剩余的桶数

问题在于,原来的分桶(terms 聚合)只会返回相对少量的桶(不是数百万),所以只会评估少量的用户。 实现这一目标的最佳方法是什么?

POST /reports/_search
{
     "size": 0,
     "query": {
         "range": {
             "timestamp": {
                 "gte": "2020-01-01T00:00:00.000Z",
                 "lte": "2020-12-24T23:59:59.999Z",
                 "format": "strict_date_optional_time"
             }
         }
     },
     "aggs": {
         "distinctIds_less_than_monthly": {
             "terms": {
                 "field": "userId" // this will only return a small amount of buckets
             },
             "aggs": {
                 "less_than_monthly": {
                     "bucket_selector": {
                         "buckets_path": {
                             "distinctUsers": "distinctUsers_less_than_monthly.value"
                         },
                         "script": "params.distinctUsers > 1000 && params.distinctUsers < 1500"
                     }
                 },
                 "distinctUsers_less_than_monthly": {
                     "value_count": {
                         "field": "userId"
                     }
                 }                 
             }
         },
         "userCount_less_than_monthly": {
             "stats_bucket": {
                 "buckets_path": "distinctIds_less_than_monthly._count"
             }
         }
     }
}

【问题讨论】:

    标签: database elasticsearch elasticsearch-aggregation


    【解决方案1】:

    我基本上看到了 3 种优化,所有这些优化都共享一个地图 → 组合方法:

    1. 用您选择的语言编写一个脚本,以将 1Y 范围划分为月/周,运行查询并合并结果。
    2. 在运行术语聚合之前应用某种过滤器 - 首先计算最有价值用户的用户统计信息(根据收入、每日活跃使用情况等选择他们),然后对于其余的。然后合并。
    3. Pre-group 用户,例如,姓名首字母,并在这些组中运行 terms aggs。然后合并。

    【讨论】:

    • 所以基本上前两个选项建议将范围/用户分成组。问题是我将有很多组(例如数千个),在这种情况下,它需要从客户端到 elasticsearch 的数千次(如果不是更多)往返来计算每个可能需要几个小时的组,或者少量组,但每个组的每个组仍然有超过 10000 个用户,这仍然会产生“桶太多”错误。第三个选项似乎只是添加了一个中间部门,我不确定它会有什么帮助。
    • 首先必须一次检索这么多桶的用例是什么?这是某种年度报告吗?你真的需要那么多吗?
    • 是的,它是一份定期报告,其期间由最终用户定义。我们不需要每个桶单独,但我们需要对桶进行计数(如原帖中所述),因此所有桶都聚合成一个数字。
    • 我明白了,但一个最终用户不会将整个事情限制在一个 userId 上吗?此外,我真的会去每周一次的桶——你有 52 个请求,肯定不会花几天的时间。再加上将最大存储桶增加到 50K,不应该让您的集群停机。我偶尔也会做同样的事情。
    • 最终用户是管理员用户,需要获取特定时间段内所有用户的概览。该系统每天被数百万或数百万用户使用,因此即使将其分解为数周(甚至数天)后,每个请求仍将有数百万用户(存储桶太多)
    猜你喜欢
    • 1970-01-01
    • 2017-09-22
    • 1970-01-01
    • 2020-09-04
    • 1970-01-01
    • 2014-10-11
    • 2014-07-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多