【问题标题】:Range ElasticSearch Aggregation范围 ElasticSearch 聚合
【发布时间】:2018-11-28 22:52:36
【问题描述】:

我需要在 ElasticSearch 中计算一个管道聚合,但我不知道如何表达它。

每个文档都有一个电子邮件地址和一个金额。我需要输出按唯一电子邮件分组的数量范围桶。

{ "0 - 99": 300, "100 - 400": 100 ...}

基本上是预期的输出(密钥将在我的应用程序代码中转换),表明 300 封唯一电子邮件已累计收到所有文档中至少 99 封(数量)。

直观地说,我希望得到如下查询。但是,范围似乎不是存储桶聚合(或允许存储桶路径)。

这里的正确方法是什么?

{
 aggs: {
   users: {
     terms: {
       field: "email"
     },
     aggs: {
       amount_received: {
         sum: {
           field: "amount"
         }
       }
     }
   },
   amount_ranges: {
     range: {
       buckets_path: "users>amount_received",
       ranges: [
           { to: 99.0 },
           { from: 100.0, to: 299.0 },
           { from: 300.0, to: 599.0 },
           { from: 600.0 }
       ]
     }
   }
}
  }

【问题讨论】:

    标签: elasticsearch elasticsearch-aggregation


    【解决方案1】:

    没有直接执行此操作的管道聚合。但是,我想我想出了一个适合您需求的解决方案,就像这样。这个想法是重复相同的 terms/sum 聚合,然后对您感兴趣的每个范围使用 bucket_selector 管道聚合。

    POST index/_search
    {
      "size": 0,
      "aggs": {
        "users_99": {
          "terms": {
            "field": "email",
            "size": 1000
          },
          "aggs": {
            "amount_received": {
              "sum": {
                "field": "amount"
              }
            },
            "-99": {
              "bucket_selector": {
                "buckets_path": {
                  "amountReceived": "amount_received"
                },
                "script": "params.amountReceived < 100"
              }
            }
          }
        },
        "users_100_299": {
          "terms": {
            "field": "email",
            "size": 1000
          },
          "aggs": {
            "amount_received": {
              "sum": {
                "field": "amount"
              }
            },
            "100-299": {
              "bucket_selector": {
                "buckets_path": {
                  "amountReceived": "amount_received"
                },
                "script": "params.amountReceived >= 100 && params.amountReceived < 300"
              }
            }
          }
        },
        "users_300_599": {
          "terms": {
            "field": "email",
            "size": 1000
          },
          "aggs": {
            "amount_received": {
              "sum": {
                "field": "amount"
              }
            },
            "300-599": {
              "bucket_selector": {
                "buckets_path": {
                  "amountReceived": "amount_received"
                },
                "script": "params.amountReceived >= 300 && params.amountReceived < 600"
              }
            }
          }
        },
        "users_600": {
          "terms": {
            "field": "email",
            "size": 1000
          },
          "aggs": {
            "amount_received": {
              "sum": {
                "field": "amount"
              }
            },
            "600": {
              "bucket_selector": {
                "buckets_path": {
                  "amountReceived": "amount_received"
                },
                "script": "params.amountReceived >= 600"
              }
            }
          }
        }
      }
    }
    

    在结果中,users_99 中的桶数将是数量小于 99 的唯一电子邮件的数量。同样,users_100_299 将包含与数量在 100 之间的唯一电子邮件一样多的桶和300。等等......

    【讨论】:

    • 可能是唯一完全使用 ES 的解决方案(没有外部 ES 步骤)。我确实对这组聚合的性能有一些尚未证实的担忧。但是,如果正在执行,@Ben 你对它很满意,那么就不用担心:-)。如果性能影响您的 ES 使用,也许考虑在 Elasticsearch 之外进行“拆分”。
    • 同意@Andrei,性能可能是一个问题,具体取决于 Ben 想要运行此查询的数据量。我们会看看他说什么。此外,创建一个新的bucket_range 管道聚合会很好,我可能很快会提交一个功能请求。
    • Val,我确实考虑过这样的解决方案,但希望有更内置的方法。我一定会尝试一下,看看性能是否可以接受。谢谢!
    • @Ben 你能试试这个吗?
    • @Val,我可以试一试。如果我可以导出每个存储桶的文档数量,而不是为每个存储桶返回一个文档数组,那就太好了。正如您所指出的,为每个存储桶提取所有记录(超出您放置的任意 1k 大小)可能会产生性能问题。我想推导出这个计数最终是不可能的。
    猜你喜欢
    • 2016-04-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-02
    • 1970-01-01
    • 2020-12-19
    • 2018-01-09
    • 1970-01-01
    相关资源
    最近更新 更多