Elasticsearch 中的聚合(Aggregations)技术详解
本文来自于我关于 Elasticsearch 的系列文章。欢迎阅读、点评与交流~ 1、Elasticsearch 深度解析:从核心原理到开发者实战 2、深入理解倒排索引(Inverted Index):搜索引擎的核心数据结构 3、Elasticsearch 中的聚合(Aggregations)技术详解 4、Elasticsearch 列式存储详解:Doc Values 的原理与实践

文章目录
- Elasticsearch 中的聚合(Aggregations)技术详解
-
- 1. 聚合概述
- 2. 聚合的分类
- 3. 核心概念
- 4. 常用聚合详解
-
- 4.1 指标聚合(Metric Aggregations)
- 4.2 桶聚合(Bucket Aggregations)
- 4.3 管道聚合(Pipeline Aggregations)
- 5. 聚合语法结构
- 6. 执行原理与数据结构
-
- 6.1 Doc Values 与 Fielddata
- 6.2 分布式执行流程
- 6.3 深度聚合与延迟
- 7. 性能优化与注意事项
-
- 7.1 通用优化建议
- 7.2 内存与 OOM 风险
- 7.3 实时性与缓存
- 7.4 精确度与近似值
- 8. 典型应用场景
- 9. 示例:复杂聚合实战
- 10. 总结
Elasticsearch 的聚合(Aggregations)是其核心功能之一,用于对索引中的数据进行
统计分析、分组、计算和转换,类似于 SQL 中的
GROUP BY、
COUNT、
SUM、
AVG 以及窗口函数。聚合与搜索查询并行工作,可以在同一个请求中同时返回搜索结果和统计结果,非常适合构建仪表盘、数据报表、实时分析等场景。
1. 聚合概述
- 定义:聚合是一组对文档集合进行数据提取和计算的框架,它基于查询(query)过滤后的文档集,执行各种统计分析。
- 与搜索的关系:聚合可以独立使用(size:0 只返回聚合结果),也可以与搜索查询结合(返回命中文档的同时返回聚合)。
- 特点:
- 实时计算(基于倒排索引和 Doc Values)
- 支持嵌套(在桶内再建桶或计算指标)
- 支持管道聚合(对聚合结果再次聚合)
- 分布式并行计算(分片级别聚合 + 协调节点合并)
2. 聚合的分类
Elasticsearch 官方将聚合分为四大类,最常用的是前三类:
| 指标聚合 | 对文档的某个字段进行数学计算,返回单值或多值指标。 | avg, sum, min, max, stats, cardinality |
| 桶聚合 | 将文档划分到不同的桶(分组)中,每个桶代表一个类别或区间。 | terms, range, histogram, date_histogram, filter |
| 管道聚合 | 基于其他聚合的输出结果进行二次聚合,如计算导数、累积和、移动平均等。 | derivative, cumulative_sum, moving_avg, bucket_script |
| 矩阵聚合 | 对多个字段的值进行矩阵运算,如计算相关系数。较少用。 | matrix_stats |
3. 核心概念
- 桶(Bucket):一组满足特定条件的文档集合。桶聚合会创建多个桶,每个桶有一个键(key)和文档列表(逻辑上)。例如按 country 字段分桶,每个国家是一个桶。
- 指标(Metric):对桶内文档的数值字段进行统计计算。指标聚合可以计算平均值、总和、最大值等。
- 嵌套(Nesting):桶内可以嵌套子聚合(子桶或子指标),实现多层级分组统计。例如先按国家分桶,再在每个国家桶内按城市分桶,最后计算平均年龄。
- 元数据(Metadata):可以给聚合添加自定义元数据,便于识别。
4. 常用聚合详解
4.1 指标聚合(Metric Aggregations)
| avg | 平均值 | \”avg_price\”: { \”avg\”: { \”field\”: \”price\” } } |
| sum | 总和 | \”total_revenue\”: { \”sum\”: { \”field\”: \”revenue\” } } |
| min / max | 最小值 / 最大值 | \”min_date\”: { \”min\”: { \”field\”: \”timestamp\” } } |
| stats | 一次性返回 count, min, max, avg, sum | \”price_stats\”: { \”stats\”: { \”field\”: \”price\” } } |
| extended_stats | 在 stats 基础上增加方差、标准差、标准差范围等 | \”price_ext_stats\”: { \”extended_stats\”: { \”field\”: \”price\” } } |
| cardinality | 去重计数(近似值,基于 HyperLogLog++) | \”unique_users\”: { \”cardinality\”: { \”field\”: \”user_id\” } } |
| value_count | 统计某字段非空的文档数 | \”non_null_prices\”: { \”value_count\”: { \”field\”: \”price\” } } |
| top_hits | 返回桶内最匹配的若干文档(支持排序、分页、高亮) | 常嵌套在桶聚合中,获取每个分组的前 N 条记录 |
| percentiles | 百分位数统计 | \”price_percentiles\”: { \”percentiles\”: { \”field\”: \”price\” } } |
| scripted_metric | 使用脚本自定义指标计算(灵活但消耗大) | 支持 Map/Combine/Reduce 阶段 |
4.2 桶聚合(Bucket Aggregations)
| terms | 根据字段值分桶,返回每个值的文档数。常用于枚举、标签、类别。 | \”by_category\”: { \”terms\”: { \”field\”: \”category\”, \”size\”: 10 } } |
| filter | 只创建一个桶,包含匹配给定查询的文档。常用于全局过滤。 | \”high_price\”: { \”filter\”: { \”range\”: { \”price\”: { \”gt\”: 100 } } } } |
| filters | 多个过滤器,每个过滤器创建一个桶。 | \”price_ranges\”: { \”filters\”: { \”filters\”: { \”cheap\”: {…}, \”expensive\”: {…} } } } |
| range | 按数值范围分桶,可自定义多个区间。 | \”price_range\”: { \”range\”: { \”field\”: \”price\”, \”ranges\”: [ { \”to\”: 50 }, { \”from\”: 50, \”to\”: 100 } ] } } |
| date_range | 日期范围分桶,支持日期数学表达式(now-1d 等)。 | \”date_range\”: { \”date_range\”: { \”field\”: \”timestamp\”, \”ranges\”: [ { \”from\”: \”2024-01-01\” } ] } } |
| histogram | 等间隔数值直方图(固定步长)。 | \”price_hist\”: { \”histogram\”: { \”field\”: \”price\”, \”interval\”: 10 } } |
| date_histogram | 时间直方图(固定时间间隔:分钟、小时、天等)。 | \”sales_over_time\”: { \”date_histogram\”: { \”field\”: \”timestamp\”, \”calendar_interval\”: \”day\” } } |
