0%

聚合操作

Elasticsearch 聚合操作(Aggregations)详解:从基础到高级分析

聚合操作是 Elasticsearch 中用于数据分析的核心功能,能够对查询结果进行统计、分组、计算等汇总操作,类似 SQL 中的 GROUP BYSUMAVG 等,但功能更强大、更灵活。根据操作方式和用途,聚合可分为四大类:分组聚合(Bucketing)度量聚合(Metric)矩阵聚合(Matrix)管道聚合(Pipeline)

聚合操作基础语法

Elasticsearch 聚合通过 aggs(或全称 aggregations)关键字定义,基本结构如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
{
"aggs": { // 聚合操作入口(可缩写为aggs)
"<聚合名称>": { // 自定义聚合的逻辑名称(如"avg_price")
"<聚合类型>": { // 聚合类型(如avg、terms、date_histogram)
<聚合参数> // 聚合的具体配置(如字段、间隔等)
},
"aggs": { // 子聚合(可选,基于当前聚合结果进一步分析)
"<子聚合名称>": { ... }
}
}
},
"size": 0 // 可选,设置为0仅返回聚合结果,不返回原始文档
}
  • 核心特点:支持多层嵌套(子聚合),可基于分组结果再进行度量,或基于度量结果再进行计算。
  • 适用场景:统计分析(如销售额总和)、分组统计(如按类别统计销量)、趋势分析(如按日统计访问量)等。

度量聚合(Metric)

度量聚合用于对文档中的数值型字段进行计算,返回单个或多个统计值(如平均值、最大值)。分为单值度量(返回一个值)和多值度量(返回多个相关值)。

单值度量聚合

(1)平均值(avg)

计算指定字段的平均值。

1
2
3
4
5
6
7
8
9
GET products/_search
{
"size": 0,
"aggs": {
"avg_price": { // 聚合名称
"avg": { "field": "price" } // 计算price字段的平均值
}
}
}

响应示例:

1
2
3
4
5
{
"aggregations": {
"avg_price": { "value": 250.5 } // 平均值为250.5
}
}
(2)基数(cardinality)

计算指定字段的不同值的近似数量(类似 COUNT(DISTINCT 字段))。

1
2
3
4
5
6
7
8
9
10
11
12
GET products/_search
{
"size": 0,
"aggs": {
"distinct_categories": {
"cardinality": {
"field": "category.keyword", // 对category字段去重计数
"precision_threshold": 1000 // 精度阈值(低于此值时结果精确)
}
}
}
}
  • 适用场景:统计不同类别、不同用户的数量(性能优于精确计数,适合大数据量)。
(3)最大值(max)、最小值(min)、求和(sum)
1
2
3
4
5
6
7
8
9
GET products/_search
{
"size": 0,
"aggs": {
"max_price": { "max": { "field": "price" } }, // 最大值
"min_price": { "min": { "field": "price" } }, // 最小值
"total_sales": { "sum": { "field": "sales" } } // 总和
}
}

多值度量聚合

(1)统计(stats)

一次性返回字段的计数、最大值、最小值、平均值、总和

1
2
3
4
5
6
7
GET products/_search
{
"size": 0,
"aggs": {
"price_stats": { "stats": { "field": "price" } }
}
}

响应示例:

1
2
3
4
5
6
7
8
9
10
11
{
"aggregations": {
"price_stats": {
"count": 100, // 文档总数
"min": 50.0, // 最小值
"max": 500.0, // 最大值
"avg": 250.5, // 平均值
"sum": 25050.0 // 总和
}
}
}
(2)百分比(percentiles)

计算数值字段的百分比分布(默认返回 1%、5%、25%、50%、75%、95%、99% 分位值)。

1
2
3
4
5
6
7
8
9
10
11
12
GET logs/_search
{
"size": 0,
"aggs": {
"load_time_percentiles": {
"percentiles": {
"field": "load_time", // 计算加载时间的百分比
"percents": [90, 95, 99] // 只返回90%、95%、99%分位值
}
}
}
}

响应示例:

1
2
3
4
5
6
7
8
9
10
11
{
"aggregations": {
"load_time_percentiles": {
"values": {
"90.0": 150.0, // 90%的请求加载时间≤150ms
"95.0": 200.0, // 95%的请求加载时间≤200ms
"99.0": 300.0 // 99%的请求加载时间≤300ms
}
}
}
}
(3)最高命中(top_hits)

返回每个分组中相关性最高的文档(如每个类别中销量最高的商品)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
GET products/_search
{
"size": 0,
"aggs": {
"by_category": {
"terms": { "field": "category.keyword" }, // 按类别分组
"aggs": {
"top_selling": {
"top_hits": { // 返回每个分组中得分最高的1条文档
"size": 1,
"_source": ["name", "price", "sales"], // 只返回指定字段
"sort": [{ "sales": { "order": "desc" } }] // 按销量降序
}
}
}
}
}
}

分组聚合(Bucketing)

分组聚合基于字段值或条件将文档划分为多个 “桶(Bucket)”,每个桶包含满足条件的文档。支持子聚合,可对每个桶进一步分析。

常用分组聚合

(1)索引词分组(terms)

按字段的精确值分组(类似 GROUP BY 字段),适用于 keywordinteger 等字段。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
GET products/_search
{
"size": 0,
"aggs": {
"by_category": { // 按类别分组
"terms": {
"field": "category.keyword", // 必须使用keyword类型(不分词)
"size": 10, // 返回前10个分组
"order": { "avg_price": "desc" } // 按子聚合avg_price降序排序
},
"aggs": {
"avg_price": { "avg": { "field": "price" } } // 每个分组的平均价格
}
}
}
}

响应示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{
"aggregations": {
"by_category": {
"buckets": [
{
"key": "electronics", // 分组值(类别)
"doc_count": 50, // 该组文档数
"avg_price": { "value": 300.0 } // 子聚合结果
},
{
"key": "clothing",
"doc_count": 30,
"avg_price": { "value": 150.0 }
}
]
}
}
}
(2)直方图(histogram)

数值间隔分组(如价格每 50 元一组),适用于连续数值字段。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
GET products/_search
{
"size": 0,
"aggs": {
"price_ranges": {
"histogram": {
"field": "price",
"interval": 50 // 间隔为50(即0-50、50-100、...)
},
"aggs": {
"total_sales": { "sum": { "field": "sales" } } // 每组的总销量
}
}
}
}
(3)日期直方图(date_histogram)

时间间隔分组(如按天、月统计),适用于 date 类型字段。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
GET logs/_search
{
"size": 0,
"aggs": {
"daily_visits": {
"date_histogram": {
"field": "visit_time",
"interval": "day", // 按天分组
"format": "yyyy-MM-dd", // 日期格式
"missing": "1970-01-01" // 缺失值填充
},
"aggs": {
"pv": { "value_count": { "field": "user_id" } } // 每日访问量
}
}
}
}
(4)范围分组(range)

自定义范围分组(如价格 0-100、100-200、200 以上)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
GET products/_search
{
"size": 0,
"aggs": {
"price_buckets": {
"range": {
"field": "price",
"ranges": [
{ "to": 100 }, // 0-100
{ "from": 100, "to": 200 }, // 100-200
{ "from": 200 } // 200以上
]
}
}
}
}

特殊分组聚合

(1)过滤分组(filter)

仅对满足过滤条件的文档进行聚合(类似 WHERE 子句)。

1
2
3
4
5
6
7
8
9
10
11
12
GET products/_search
{
"size": 0,
"aggs": {
"expensive_products": {
"filter": { "range": { "price": { "gte": 200 } } }, // 只考虑价格≥200的商品
"aggs": {
"avg_sales": { "avg": { "field": "sales" } } // 计算这些商品的平均销量
}
}
}
}
(2)嵌套分组(nested)

对嵌套类型(nested)的字段进行分组(需指定嵌套路径)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
GET orders/_search
{
"size": 0,
"aggs": {
"nested_products": {
"nested": { "path": "products" }, // 嵌套字段路径
"aggs": {
"by_product": {
"terms": { "field": "products.name.keyword" }, // 按嵌套的商品名称分组
"aggs": {
"total_quantity": { "sum": { "field": "products.quantity" } } // 总数量
}
}
}
}
}
}

管道聚合(Pipeline)

管道聚合不直接处理文档,而是基于其他聚合的结果进行二次计算,分为父聚合(基于子聚合结果)和兄弟聚合(基于同级聚合结果)。

移动平均(moving_avg)

对时序数据计算滑动窗口的平均值(如按日销量计算 5 天移动平均)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
GET sales/_search
{
"size": 0,
"aggs": {
"daily_sales": {
"date_histogram": { // 按日分组计算销量总和
"field": "date",
"interval": "day"
},
"aggs": {
"total": { "sum": { "field": "amount" } }, // 每日销售额
"avg_5d": { // 基于total计算5天移动平均
"moving_avg": { "buckets_path": "total", "window": 5 }
}
}
}
}
}

差值(derivative)

计算相邻分组的差值(如每日销量较前一天的变化量)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
GET sales/_search
{
"size": 0,
"aggs": {
"daily_sales": {
"date_histogram": { "field": "date", "interval": "day" },
"aggs": {
"total": { "sum": { "field": "amount" } },
"day_over_day": { // 计算相邻两天的销售额差值
"derivative": { "buckets_path": "total" }
}
}
}
}
}

分组选择器(bucket_selector)

过滤掉不满足条件的分组(如只保留销售额≥1000 的日期)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
GET sales/_search
{
"size": 0,
"aggs": {
"daily_sales": {
"date_histogram": { "field": "date", "interval": "day" },
"aggs": {
"total": { "sum": { "field": "amount" } },
"filter_high_sales": { // 只保留total≥1000的分组
"bucket_selector": {
"buckets_path": { "sales": "total" },
"script": "params.sales >= 1000"
}
}
}
}
}
}

聚合操作的关键注意事项

  1. 字段类型限制
    • 度量聚合仅支持数值型字段(integerdoubledate 等)。
    • 分组聚合中,terms 需使用 keyword 类型(不分词),否则可能因分词导致分组混乱。
  2. 性能优化
    • 大数据量下,terms 聚合可通过 size 限制返回分组数,避免内存溢出。
    • 基数聚合(cardinality)使用近似算法,通过 precision_threshold 平衡精度与性能。
  3. 嵌套聚合深度
    过度嵌套(如多层 terms 聚合)可能导致性能下降,建议控制嵌套层级(通常不超过 3 层)。
  4. 与查询结合
    聚合默认基于所有文档,若需过滤文档,可在 query 中添加条件(聚合仅作用于匹配的文档)

欢迎关注我的其它发布渠道

表情 | 预览
快来做第一个评论的人吧~
Powered By Valine
v1.3.10