写点什么

大数据 -177 Elasticsearch 聚合实战:指标聚合 + 桶聚合完整用法与 DSL 解析

作者:武子康
  • 2025-12-08
    山东
  • 本文字数:3299 字

    阅读完需:约 11 分钟

大数据-177 Elasticsearch 聚合实战:指标聚合 + 桶聚合完整用法与 DSL 解析

TL;DR

  • 场景:在日志分析、报表统计、运营看板中,需要用 Elasticsearch 聚合替代数据库 GROUP BY/COUNT。

  • 结论:合理组合指标聚合和桶聚合,能在一次查询中完成统计、分组、过滤和「类 HAVING」逻辑。

  • 产出:给出从 max/sum/stats 到 range/bucket_selector 的完整示例,可直接改字段名复制到生产环境使用。


版本矩阵


聚合介绍

Elasticsearch 的聚合分析是一种强大的功能,允许用户在查询数据的同时对其进行统计分析、分组计算和排序,类似于 SQL 中的 GROUP BY 和 COUNT() 等操作。聚合分析包括两个主要类别:指标聚合和桶聚合。在聚合的基础上,你还可以进行嵌套聚合,将多个聚合组合在一起,从而构建复杂的分析查询。


聚合分析是数据库中的重要的功能特性,完成对一个查询的数据集中数据的聚合计算,如:找出某个字段(或计算表达式的结果)的最大值、最小值、计算和、平均值等。Elasticsearch 作为搜索引擎兼数据库,同样提供了强大的聚合分析能力。对一个数据集求最大、最小、和、平均值等指标的聚合,在 ES 中称为指标聚合 metric,而关系型数据库中除了有桶聚合函数外,还可以对查询出的数据进行分组 GROUP BY,再在组上进行指标聚合,在 ES 中 GROUP BY 称为分桶,桶聚合 BucketingElasticsearch 聚合分析语法,在查询请求体中 aggregations 节点,按如下语法定义聚合分析:


"aggregations" : {  "<aggregation_name>" : { <!--聚合的名字 -->    "<aggregation_type>" : { <!--聚合的类型 -->      <aggregation_body> <!--聚合体:对哪些字段进行聚合 -->    }    [,"meta" : { [<meta_data_body>] } ]? <!--元 -->    [,"aggregations" : { [<sub_aggregation>]+ } ]? <!--在聚合里面在定义子聚合 -->  }}
复制代码


说明:aggregatations 也可以简写做:aggs

指标聚合

max min sum avg


指标聚合 (Metrics Aggregations)指标聚合的主要功能是计算某个字段的数值统计结果。常见的指标聚合包括求和、平均值、最大值、最小值、计数等。它们通常用于返回单个数值结果。


常用的指标聚合包括:


  • avg:计算数值字段的平均值。

  • sum:计算数值字段的总和。

  • min:返回数值字段的最小值。

  • max:返回数值字段的最大值。

  • value_count:计算某个字段的值的数量。

  • stats:返回字段的统计信息,包括最小值、最大值、平均值、总和和数量。

  • extended_stats:比 stats 聚合提供更详细的统计信息,如标准差和方差。

查询最贵的

# price的最大值 POST /book/_search{  "size": 0,  "aggs": {    "max_price": {      "max": {        "field": "price"      }    }  }}
复制代码


执行结果如下图所示:


price 大于 100 的

# 使用 _count 计算数量POST /book/_count{  "query": {    "range": {      "price" : {        "gt":100      }    }  }}
复制代码


执行结果如下:


统计字段有值

# 通过聚合的方式 统计 price 有值的POST /book/_search{  "size": 0,  "aggs": {    "book_nums": {      "value_count": {        "field": "price"      }    }  }}
复制代码


执行结果如下图所示:


去重计数

# agg 聚合 去重数量POST /book/_search?size=0{  "aggs": {    "price_count": {      "cardinality": {        "field": "price"      }    }  }}
复制代码


执行的结果如下图所示:


统计计数

stats 可以统计好几个值:


  • max

  • min

  • count

  • avg

  • sum


# statsPOST /book/_search?size=0{  "aggs": {    "price_stats": {      "stats": {        "field": "price"      }    }  }}
复制代码


运行结果如下图所示:


扩展统计

Extended Stats,高级统计,比 stats 多 4 个统计结果:


  • 平方和

  • 方差

  • 标准差

  • 平均值加/减两个标准差的区间


# extended statsPOST /book/_search?size=0{  "aggs": {    "price_stats": {      "extended_stats": {        "field": "price"      }    }  }}
复制代码

占比百分位

Percentiles 占比百分位对应的值统计


# 占比百分位POST /book/_search?size=0{  "aggs": {    "price_percents": {      "percentiles": {        "field": "price"      }    }  }}
复制代码


执行结果如下图所示:



当然,我们也可以指定分位值:


# 指定分位值POST /book/_search?size=0{  "aggs": {    "price_percents": {      "percentiles": {        "field": "price",        "percents" : [75, 99, 99.9]      }    }  }}
复制代码


运行结果如下图:


统计值小于等于指定值的文档占比

统计 price 小于 100 和 200 的文档的占比


POST /book/_search?size=0{  "aggs": {    "gge_perc_rank": {      "percentile_ranks": {        "field": "price",        "values": [          100,200        ]      }    }  }}
复制代码


运行结果如下图所示:


桶聚合

Bucket Aggregations,桶聚合。它执行的是对文档分组的操作(与 SQL 中的 GROUP BY 类似),把满足相关特性的文档分到一个桶里,即桶分,输出结果往往是一个包含多个文档的桶(一个桶就是一个 GROUP)


  • bucket 一个数据分组

  • metric 对一个数据分组执行的统计


桶聚合的目的是根据某些条件对文档进行分组,每个组称为一个“桶”。每个桶包含符合特定条件的文档集合,可以对每个桶进一步执行其他聚合分析(如指标聚合或嵌套的桶聚合)。


常见的桶聚合包括:


  • terms:按某个字段的不同值进行分组(类似 SQL 的 GROUP BY)。

  • range:根据数值范围对字段进行分组。

  • date_histogram:基于时间字段按固定时间间隔分组。

  • histogram:基于数值字段按固定间隔分组。

  • filter:根据查询条件过滤文档。

  • filters:根据多个查询条件将文档分为多个不同的桶。

  • geo_distance:基于地理位置和距离的范围来分组。


POST /book/_search{  "size": 0,  "aggs": {    "group_by_price": {      "range": {        "field": "price",        "ranges": [          {            "from": 0,            "to": 200          },          {            "from": 200,            "to": 400          },          {            "from": 400,            "to": 1000          }        ]      },      "aggs": {        "average_price": {          "avg": {            "field": "price"          }        }      }    }  }}
复制代码


执行的结果如下图所示:



我们也可以实现 having 的效果:


POST /book/_search{  "size": 0,  "aggs": {    "group_by_price": {      "range": {        "field": "price",        "ranges": [          {            "from": 0,            "to": 200          },          {            "from": 200,            "to": 400          },          {            "from": 400,            "to": 1000          }        ]      },      "aggs": {        "average_price": {          "avg": {            "field": "price"          }        },        "having": {          "bucket_selector": {            "buckets_path": {              "avg_price": "average_price"            },            "script": {              "source": "params.avg_price >= 200 "            }          }        }      }    }  }}
复制代码


执行结果如下图所示:


错误速查

其他系列

🚀 AI 篇持续更新中(长期更新)

AI 炼丹日志-29 - 字节跳动 DeerFlow 深度研究框斜体样式架 私有部署 测试上手 架构研究,持续打造实用 AI 工具指南!AI 研究-132 Java 生态前沿 2025:Spring、Quarkus、GraalVM、CRaC 与云原生落地🔗 AI模块直达链接

💻 Java 篇持续更新中(长期更新)

Java-180 Java 接入 FastDFS:自编译客户端与 Maven/Spring Boot 实战 MyBatis 已完结,Spring 已完结,Nginx 已完结,Tomcat 已完结,分布式服务已完结,Dubbo 已完结,MySQL 已完结,MongoDB 已完结,Neo4j 已完结,FastDFS 已完结,OSS 正在更新... 深入浅出助你打牢基础!🔗 Java模块直达链接

📊 大数据板块已完成多项干货更新(300 篇):

包括 Hadoop、Hive、Kafka、Flink、ClickHouse、Elasticsearch 等二十余项核心组件,覆盖离线+实时数仓全栈!大数据-278 Spark MLib - 基础介绍 机器学习算法 梯度提升树 GBDT 案例 详解🔗 大数据模块直达链接

发布于: 刚刚阅读数: 4
用户头像

武子康

关注

永远好奇 无限进步 2019-04-14 加入

Hi, I'm Zikang,好奇心驱动的探索者 | INTJ / INFJ 我热爱探索一切值得深究的事物。对技术、成长、效率、认知、人生有着持续的好奇心和行动力。 坚信「飞轮效应」,相信每一次微小的积累,终将带来深远的改变。

评论

发布
暂无评论
大数据-177 Elasticsearch 聚合实战:指标聚合 + 桶聚合完整用法与 DSL 解析_Java_武子康_InfoQ写作社区