一架梯子,一头程序猿,仰望星空!

golang elasticsearch 桶聚合(bucket)


Elasticsearch桶聚合,目的就是数据分组,先将数据按指定的条件分成多个组,然后对每一个组进行统计。

不了解Elasticsearch桶聚合概念,可以先学习下Elasticsearch桶聚合教程

下面分别介绍golang elasticsearch桶聚合的写法

1.Terms聚合

package main

import (
	"context"
	"fmt"
	"github.com/olivere/elastic/v7"
	"log"
)

func main() {
	// 创建ES client
	client, err := elastic.NewClient()
	if err != nil {
		// Handle error
		panic(err)
	}

	// 执行ES请求需要提供一个上下文对象
	ctx := context.Background()

	// 创建Terms桶聚合
	aggs := elastic.NewTermsAggregation().
		Field("shop_id") // 根据shop_id字段值,对数据进行分组

	searchResult, err := client.Search().
		Index("shops"). // 设置索引名
		Query(elastic.NewMatchAllQuery()). // 设置查询条件
		Aggregation("shop", aggs). // 设置聚合条件,并为聚合条件设置一个名字
		Size(0). // 设置分页参数 - 每页大小,设置为0代表不返回搜索结果,仅返回聚合分析结果
		Do(ctx) // 执行请求

	if err != nil {
		// Handle error
		panic(err)
	}

	// 使用Terms函数和前面定义的聚合条件名称,查询结果
	agg, found := searchResult.Aggregations.Terms("shop")
	if !found {
		log.Fatal("没有找到聚合数据")
	}

	// 遍历桶数据
	for _, bucket := range agg.Buckets {
		// 每一个桶都有一个key值,其实就是分组的值,可以理解为SQL的group by值
		bucketValue := bucket.Key

		// 打印结果, 默认桶聚合查询,都是统计文档总数
		fmt.Printf("bucket = %q 文档总数 = %d\n", bucketValue, bucket.DocCount)
	}
}

2.Histogram聚合

// 创建Histogram桶聚合
aggs := elastic.NewHistogramAggregation().
		Field("price"). // 根据price字段值,对数据进行分组
		Interval(50) //  分桶的间隔为50,意思就是price字段值按50间隔分组

searchResult, err := client.Search().
		Index("order"). // 设置索引名
		Query(elastic.NewMatchAllQuery()). // 设置查询条件
		Aggregation("prices", aggs). // 设置聚合条件,并为聚合条件设置一个名字
		Size(0). // 设置分页参数 - 每页大小,设置为0代表不返回搜索结果,仅返回聚合分析结果
		Do(ctx) // 执行请求

if err != nil {
	// Handle error
	panic(err)
}

// 使用Histogram函数和前面定义的聚合条件名称,查询结果
agg, found := searchResult.Aggregations.Histogram("prices")
if !found {
	log.Fatal("没有找到聚合数据")
}

// 遍历桶数据
for _, bucket := range agg.Buckets {
	// 每一个桶都有一个key值,其实就是分组的值,可以理解为SQL的group by值
	bucketValue := bucket.Key

	// 打印结果, 默认桶聚合查询,都是统计文档总数
	fmt.Printf("bucket = %q 文档总数 = %d\n", bucketValue, bucket.DocCount)
}

3.Date histogram聚合

// 创DateHistogram桶聚合
aggs := elastic.NewDateHistogramAggregation().
		Field("date"). // 根据date字段值,对数据进行分组
		//  分组间隔:month代表每月、支持minute(每分钟)、hour(每小时)、day(每天)、week(每周)、year(每年)
		CalendarInterval("month").
		// 设置返回结果中桶key的时间格式
		Format("yyyy-MM-dd")

searchResult, err := client.Search().
		Index("order"). // 设置索引名
		Query(elastic.NewMatchAllQuery()). // 设置查询条件
		Aggregation("sales_over_time", aggs). // 设置聚合条件,并为聚合条件设置一个名字
		Size(0). // 设置分页参数 - 每页大小,设置为0代表不返回搜索结果,仅返回聚合分析结果
		Do(ctx) // 执行请求

if err != nil {
	// Handle error
	panic(err)
}

// 使用DateHistogram函数和前面定义的聚合条件名称,查询结果
agg, found := searchResult.Aggregations.DateHistogram("sales_over_time")
if !found {
	log.Fatal("没有找到聚合数据")
}

// 遍历桶数据
for _, bucket := range agg.Buckets {
	// 每一个桶都有一个key值,其实就是分组的值,可以理解为SQL的group by值
	bucketValue := bucket.Key

	// 打印结果, 默认桶聚合查询,都是统计文档总数
	fmt.Printf("bucket = %q 文档总数 = %d\n", bucketValue, bucket.DocCount)
}

4.Range聚合

// 创Range桶聚合
aggs := elastic.NewRangeAggregation().
		Field("price"). // 根据price字段分桶
		AddUnboundedFrom(100). // 范围配置, 0 - 100
		AddRange(100.0, 200.0). // 范围配置, 100 - 200
		AddUnboundedTo(200.0) // 范围配置,> 200的值

searchResult, err := client.Search().
		Index("order"). // 设置索引名
		Query(elastic.NewMatchAllQuery()). // 设置查询条件
		Aggregation("price_ranges", aggs). // 设置聚合条件,并为聚合条件设置一个名字
		Size(0). // 设置分页参数 - 每页大小,设置为0代表不返回搜索结果,仅返回聚合分析结果
		Do(ctx) // 执行请求

if err != nil {
	// Handle error
	panic(err)
}

// 使用Range函数和前面定义的聚合条件名称,查询结果
agg, found := searchResult.Aggregations.Range("price_ranges")
if !found {
	log.Fatal("没有找到聚合数据")
}

// 遍历桶数据
for _, bucket := range agg.Buckets {
	// 每一个桶都有一个key值,其实就是分组的值,可以理解为SQL的group by值
	bucketValue := bucket.Key

	// 打印结果, 默认桶聚合查询,都是统计文档总数
	fmt.Printf("bucket = %q 文档总数 = %d\n", bucketValue, bucket.DocCount)
}

5.嵌套聚合的用法

任意聚合类型都支持嵌套,桶聚合可以嵌套桶聚合,也可以嵌套指标聚合。

例子:

// 创terms桶聚合
aggs := elastic.NewTermsAggregation().Field("shop_id")
// 创建Sum指标聚合
sumAggs := elastic.NewSumAggregation().Field("price")
// terms聚合嵌套指标聚合
aggs.SubAggregation("total_price", sumAggs)

提示:golang elasticsearch的用法,本质上还是对elasticsearch接口的封装,所以用法跟elasticsearch的语法完全一致。