ES 数据聚合
携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第3天,点击查看活动详情
1. 什么是聚合
- 聚合是对文档数据的统计、分析、计算
2. 聚合的常见种类有哪些
我们可以通过官方文档去查看所有的聚合种类www.elastic.co/guide/en/el…
- 桶(Bucket)聚合:用来对文档分组
- TermAggregation:按照文档字段值分组,例如按照国家分组、按照性别分组
- Data Histogram:按照日期阶梯分组,例如一周为一组,一月为一组
- 度量(Metric)聚合:用以计算一些值,比如:最大值、最小值、平均值等
- Avg:求平均值
- Max:求最大值
- Min:求最小值
- Stats:同时求 Max、Min、Avg、Sum等的组合求值
- 管道(PipeLine)聚合:其他聚合的结果作为基础做聚合,即组合聚合
**注意:**参加聚合的字段必须是 keyword、日期、数值、布尔类型
3. DSL 实现聚合
接下来我们同通过对现有数据按照酒店品牌对数据分组。此时可以根据酒店品牌的名称做聚合,也就是 Bucket 聚合。
3.1 Bucket 聚合语法
-
语法如下:
# 聚合文档 GET /hotel/_search { "size": 0, // 设置size为0,结果中不包含文档,只包含聚合结果 "aggs": { // 定义聚合 "brandAgg": { //给聚合起个名字 "terms": { // 聚合的类型,按照品牌值聚合,所以选择term "field": "brand", // 参与聚合的字段 "size": 20 // 希望获取的聚合结果数量 } } } }**注意:**聚合文档名字是为了让后续管道聚合能用上
-
结果如图:
3.2 聚合结果排序
默认情况下,Bucket 聚会会统计所有的 Bucket 内的文档数量,记作 count,并且按照 count 降序排序。默认降序排序
我们可以通过指定 order 数据,自定义聚合的排序方式:
-
基本语法
# 聚合文档,自定义排序规则 GET /hotel/_search { "size": 0, "aggs": { "brandAgg": { "terms": { "field": "brand", "size": 20, "order": { "_count": "asc" // 按照_count升序排列 } } } } } -
结果如图:
3.3 限定聚合范围
默认情况下,Bucket 聚合会对索引库的所有文档做聚合,但是在真实环境下,用户输入限制条件限定聚合范围,后台返回聚合结果。下面就来演示一下添加限定条件。
限定 Bucket 聚合范围
-
基本语法
我们可以限定聚合的文档返回,只要添加 query 条件即可
# 聚合文档,限定聚合范围 GET /hotel/_search { "query": { "range": { "price": { "lte": 200 // 只对200元以下的文档聚合 } } }, "size": 0, "aggs": { "brandAgg": { "terms": { "field": "brand", "size": 20 } } } } -
结果如图:
现在就是将价格在200一下的酒店做了 Bucket 聚合。
3.4 Metric 聚合语法
我们通过 Bucket 聚合统计了每个品牌的酒店数量,将它们一一化作不同的桶。接下来我们对每个不同品牌名的桶内数据进行计算,例如:结合每个相同酒店获取它们的评分的 max、min、avg 等值。
我的理解就是先按照品牌分组,再获取每组用户评分的最高分、最低分、平均分等数据
这里就要使用 Metric 聚合的 stats 聚合:就可以获取 min、max、avg 等结果。
-
语法如下:
这个 stats 聚合是在 brandAgg 的聚合内部,就是对基础的 Bucket 聚合的结果分别进行 stats 的 max、min、avg 等数值的计算。
# 嵌套聚合 matric GET /hotel/_search { "size": 0, "aggs": { "brandAgg": { "terms": { "field": "brand", "size": 20 }, "aggs": { // 是brands聚合的子聚合,也就是分组后对每组分别计算 "score_stats": { // 聚合名称 "stats": { // 聚合类型,这里stats可以计算min、max、avg等 "field": "score" // 聚合字段,这里是score } } } } } } -
结果如图
如果需要根据 Metric 聚合的结果进行排序。我们有以下语法
-
语法如下
# 嵌套聚合 matric,自定义排序 GET /hotel/_search { "size": 0, "aggs": { "brandAgg": { "terms": { "field": "brand", "size": 20, "order": { "scoreAgg.avg": "desc" } }, "aggs": { "scoreAgg": { "stats": { "field": "score" } } } } } }
3.5 小结
aggs代表聚合,与query同级,此时query的作用是?
- 限定聚合的的文档范围
聚合必须的三要素:
- 聚合名称
- 聚合类型
- 聚合字段
聚合可配置属性有:
- size:指定聚合结果数量
- order:指定聚合结果排序方式
- field:指定聚合字段
4. RestAPI 实现聚合
4.1 API 语法
聚合条件和 query 田间同级别,所以许可要用到 request.source() 来指定聚合条件。
-
聚合条件的语法
-
聚合的结果和查询的结果不同,所以需要重新写一个结果解析,不过依旧是按照 JSON 逐层解析:
-
实际代码:
/** * Bucket 聚合案例 * @throws IOException 输入输出流异常 */ @Test void AggregationTest() throws IOException { // 1. 准备 request SearchRequest request = new SearchRequest("hotel"); // 2. 准备 DSL // 2.1 设置 size request.source().size(0); // 2.2 聚合 request.source().aggregation( AggregationBuilders.terms("brandAgg"). field("brand"). size(10) ); // 3. 发送请求 SearchResponse response = client.search(request, RequestOptions.DEFAULT); // 4. 解析结果 Aggregations aggregations = response.getAggregations(); // 4.1 根据聚合名称获取聚合结果 Terms brandTerms = aggregations.get("brandAgg"); // 4.2 获取 Buckets List<? extends Terms.Bucket> buckets = brandTerms.getBuckets(); // 4.3 遍历 for (Terms.Bucket bucket : buckets) { String key = bucket.getKeyAsString(); System.out.println(key); } }