Elasticsearch 聚合学习之二:区间聚合,java 中高级面试题大全
环境信息
以下是本次实战的环境信息,请确保您的 Elasticsearch 可以正常运行:
操作系统:Ubuntu 18.04.2 LTS
JDK:1.8.0_191
Elasticsearch:6.7.1
Kibana:6.7.1
实战用的数据依然是一些汽车销售的记录,在第一章有详细的导入步骤,请参考操作,导入后您的 es 中的数据如下图:
本章概要
本篇实战的聚合操作有以下内容:
指定字段的区间聚合;
时间字段的区间聚合;
扩展实战;
接下来开始实战吧。
条形图(histogram 桶)
还记得 terms 桶么,用来将指定字段值相同的文档聚合在一个桶中,而 histogram 桶是将指定字段值在某个范围内的文档聚合在一个桶中,如下图所示,0-19999 是一个桶,11000 和 15000 在一个桶内,23000 和 31000 在一个桶内,这就是 histogram 桶:
以汽车销售记录为例做一次聚合查询,为售价创建 histogram 桶,以 20000 作为间隔,每个桶负责的区间如上图所示,相关的销售记录就会被放入对应的桶中,请求参数和说明如下:
GET /cars/transactions/_search
{
"size":0, ---令返回值的 hits 对象为空
"aggs":{ ---聚合命令
"price":{ ---聚合字段名称
"histogram": { ---桶类型
"field": "price", ---指定 price 字段的值作为判断条件
"interval": 20000 ---每个桶负责的区间大小为 20000
}
}
}
}
es 返回的数据和说明如下:
{
"took" : 57,
"timed_out" : false,
"_shards" : {
"total" : 5,
"successful" : 5,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : 8,
"max_score" : 0.0,
"hits" : [ ]
},
"aggregations" : { ---聚合结果
"price" : { ---请求参数中指定的名称
"buckets" : [ ---price 桶的数据在此数组中
{
"key" : 0.0, ---第一个桶,区间[0-19999],0.0 是起始值
"doc_count" : 3 ---这个区间有三个文档(price 值分别是 10000、12000、15000)
},
{
"key" : 20000.0, ---第二个桶,区间[20000-39999],20000.0 是起始值
"doc_count" : 4 ---这个区间有四个文档
},
{
"key" : 40000.0, ---第三个桶,区间[40000-59999],40000.0 是起始值
"doc_count" : 0 ---这个区间没有文档
},
......
控制空桶是否返回
在上面的返回值中,第三个桶中没有文档,在有的业务场景中,我们不需要没有数据的桶,此时可以用 min_doc_count 参数来控制,如果 min_doc_count 等于 2,表示桶中最少有两条记录才会出现在返回内容中,如下所示,min_doc_count 如果等于 1,那么空桶就不会被 es 返回了:
GET /cars/transactions/_search
{
"size":0,
"aggs":{
"price":{
"histogram": {
"field": "price",
"interval": 20000,
"min_doc_count": 1
}
}
}
}
返回值如下所示,没有文档的桶不再出现:
{
"took" : 16,
"timed_out" : false,
"_shards" : {
"tota
l" : 5,
"successful" : 5,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : 8,
"max_score" : 0.0,
"hits" : [ ]
},
"aggregations" : {
"price" : {
"buckets" : [
{
"key" : 0.0,
"doc_count" : 3
},
{
"key" : 20000.0,
"doc_count" : 4
},
{
"key" : 80000.0,
"doc_count" : 1
}
]
}
}
}
histogram 桶加 metrics
上面的例子返回结果只有每个桶内的文档数,也可以加入 metrics 对桶中的数据进行处理,例如计算每个区间内的最高价、最低价、平均售价,可以加入 max、min、avg 参数,如下:
GET /cars/transactions/_search
{
"size":0, ---令返回值的 hits 对象为空
"aggs":{ ---聚合命令
"price":{ ---聚合字段名称
"histogram": { ---桶类型
"field": "price", ---指定 price 字段的值作为判断条件
"interval": 20000 ---每个桶负责的区间大小为 20000
},
"aggs": { ---表示对桶内数据做 metrics
"max_price": { ---指定 metrics 处理结果的字段名
"max":{ ---metrics 类型为 max
"field": "price" ---指定取 price 字段的值做最大值比较
}
},
"min_price": { ---指定 metrics 处理结果的字段名
"min":{ ---metrics 类型为 min
"field": "price" ---指定取 price 字段的值做最小值比较
}
},
"avg_price": { ---指定 metrics 处理结果的字段名
"avg":{ ---metrics 类型为 avg
"field": "price" ---指定取 price 字段的值计算平均值
}
}
}
}
}
}
es 返回数据和说明如下,可见每个桶中的文档都做了三种 metrics 处理:
{
"took" : 17,
"timed_out" : false,
"_shards" : {
"total" : 5,
"successful" : 5,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : 8,
"max_score" : 0.0,
"hits" : [ ]
},
"aggregations" : { ---聚合结果
"price" : { ---请求参数中指定的名称
"buckets" : [ ---price 桶的数据在此数组中
{
"key" : 0.0, ---第一个区间[0-19999],0.0 是起始值
"doc_count" : 3, ---这个区间有三条记录(price 值分别是 10000、12000、15000)
"max_price" : { ---指定的 metrics 结果名称
"value" : 15000.0 ---桶中有三个文档,price 字段的最大值是 15000
},
"min_price" : {
"value" : 10000.0 ---桶中有三个文档,price 字段的最小值是 10000
},
"avg_price" : {
"value" : 12333.333333333334 ---桶中有三个文档,price 字段的平均值是 12333.333333333334
}
},
......
时间区间的桶(date_histogram)
按照时间区间聚合也是常用的功能,例如在 ELK 上查询日志,通常都是按照时间来分段的,如下图:
histogram 桶可以实现按照时间分段么?如果用毫秒数来处理,似乎是可以的,但是对年月日的处理就力不从心了,常见的时间区间处理,用 date_histogram 桶即可满足要求;
下面就是 date_histogram 桶的用法:每月销售多少台汽车:
GET /cars/transactions/_search
{
"size": 0, ---令返回值的 hits 对象为空
"aggs": { ---聚合命令
"sales": { ---聚合字段名称
"date_histogram": { ---桶类型
"field": "sold", ---用 sold 字段的值作进行时间区间判断
"interval": "month", ---间隔单位是月
"format": "yyyy-MM-dd" ---返回的数据中,时间字段格式
},
"aggs": { ---表示对桶内数据做 metrics
"max_price": { ---指定 metrics 处理结果的字段名
"max":{ ---metrics 类型为 max
"field": "price" ---指定取 price 字段的值做最大值比较
}
},
"min_price": { ---指定 metrics 处理结果的字段名
"min":{ ---metrics 类型为 min
"field": "price" ---指定取 price 字段的值做最小值比较
}
}
}
}
}
}
es 返回数据如下,篇幅所限因此略去了头部和尾部的一些信息,只看关键的:
"aggregations" : { ---聚合结果
"sales" : { ---请求参数中指定的名称
"buckets" : [ ---sales 桶的数据在此数组中
{
"key_as_string" : "2014-01-01", ---请求的 format 参数指定了 key 的格式
"key" : 1388534400000, ---真正的时间字段
"doc_count" : 1, ---2014 年 1 月份的文档数量
"max_price" : { ---2014 年 1 月的文档做了 metrics 类型为 max 的处理后,结果在此
"value" : 80000.0 ---2014 年 1 月的文档中,price 字段的最大值
},
"min_price" : { ---2014 年 1 月的文档做了 metrics 类型为 min 的处理后,结果在此
"value" : 80000.0 ---2014 年 1 月的文档中,price 字段的最大值
评论