ES Group By Sum 处理10W条以上的数据

582 阅读2分钟

有一个数据聚合的需求,es中存有10W条以上的数据,需要对这批数据做聚合查询。 为了处理这个问题,有几种方法可以考虑:

1.增加size参数,

增加terms聚合中size参数的值可以让你获取更多的桶。但是,请注意,将这个值设置得过高可能会对Elasticsearch集群的性能造成影响。

2.使用composite聚合进行分页

如果你需要处理的唯一值数量远远超过了10000,或者你希望以一种可扩展的方式处理大量的唯一值,可以使用composite聚合来进行分页处理。composite聚合允许你基于多个字段进行聚合,并且可以通过after参数来获取更多的数据,实现分页。

3.考虑调整search.max_buckets设置

在某些情况下,你可能会遇到由于聚合操作产生的总桶数超过Elasticsearch限制(默认是10000个桶)而导致的问题。这个限制可以通过更改集群设置search.max_buckets来调整。但是,请谨慎使用这个方法,因为大量的桶可能会对集

在以上方案中由于方案1和方案3都会对Elasticsearch集群的性能造成影响,最终选用方案2.

以下为golang实现代码

package main
​
import (
    "context"
    "fmt"
    "log""github.com/olivere/elastic/v7"
)
​
func main() {
    client, err := elastic.NewClient()
    if err != nil {
        log.Fatalf("Error creating the client: %s", err)
    }
​
    ctx := context.Background()
    indexName := "your_index_name" // 替换为你的索引名
    var afterKey map[string]interface{} = nilfor {
        // 构建composite aggregation,并在存在afterKey时使用它
        compositeAgg := elastic.NewCompositeAggregation().
            Size(10000).
            Sources(
                elastic.NewCompositeAggregationTermsValuesSource("your_field_name").Field("your_field_name"),
            ).
            SubAggregation("sum_field", elastic.NewSumAggregation().Field("your_sum_field_name"))
        if afterKey != nil {
            compositeAgg = compositeAgg.After(afterKey)
        }
​
        // 执行查询
        searchResult, err := client.Search().
            Index(indexName).
            Query(elastic.NewMatchAllQuery()).
            Aggregation("composite_agg", compositeAgg).
            Do(ctx)
        if err != nil {
            log.Fatalf("Error getting response: %s", err)
        }
​
        // 解析聚合结果
        agg, found := searchResult.Aggregations.Composite("composite_agg")
        if !found {
            log.Fatal("Expected to find the 'composite_agg' aggregation, but did not.")
        }
​
        for _, bucket := range agg.Buckets {
            yourFieldName, _ := bucket.Key["your_field_name"].(string)
            sumField, found := bucket.Aggregations.
            if !found {
                log.Fatal("Expected to find the 'sum_field' sub-aggregation, but did not.")
            }
            fmt.Printf("yourFieldName: %s, sum_field: %f\n", yourFieldName, *sumField.Value)
        }
​
        // 如果after_key不存在,则退出循环
        if agg.AfterKey == nil {
            break
        }
​
        // 为下一次查询准备afterKey
        afterKey = agg.AfterKey
    }
}

这个例子展示了如何构造一个查询,使用composite聚合按照一个字段进行分组,并对另一个字段求和。你可以根据需要调整size参数来控制每次请求返回的聚合桶的数量,以及通过after参数实现分页,不断获取下一批数据,直到获取完所有分组的数据。