Elasticsearch基础(十八)——聚合分析:常用metric操作
从本章开始,我将介绍Elasticsearch强大的聚合分析功能,聚合分析和SQL中的GROUP BY
非常类似。掌握聚合分析,最重要的还是实战练习,所以从本章开始,我将会通过一个案例,来介绍聚合分析的各种使用方式。
我们先来了解下聚合分析中的两个核心概念:bucket和metric。
一、核心概念
1.1 bucket
bucket代表一个数据分组。举个例子,我们有以下数据:
CITY | NAME |
---|---|
北京 | 小李 |
北京 | 小王 |
上海 | 小张 |
上海 | 小丽 |
上海 | 小陈 |
如果我们基于CITY划分buckets,就划分出来两个bucket:
- 北京bucket:包含了2个人,小李、小王
- 上海bucket:包含了3个人,小张、小丽、小陈
1.2 metric
当我们对数据进行bucket分组之后,就可以对每个bucket进行统计分析了,比如说计算一个bucket内所有数据的数量,或者计算一个bucket内所有数据的平均值、最大值、最小值。
metric,就是对一个bucket执行的某种聚合分析操作,比如说求平均值、求最大值/最大值、求数量、请和等。
二、案例背景
我们的案例以家电卖场中的电视销售为背景,这个案例将会贯彻整个聚合分析系列的所有章节。我们会对各种品牌、颜色的电视机销量和销售额进行聚合分析。
首先构建一个索引tvs
:
PUT /tvs
{
"mappings": {
"properties": {
"price": {
"type": "long"
},
"color": {
"type": "keyword"
},
"brand": {
"type": "keyword"
},
"sold_date": {
"type": "date"
}
}
}
}
批量插入一些数据:
POST /tvs/_bulk
{ "index": {}}
{ "price" : 1000, "color" : "红色", "brand" : "长虹", "sold_date" : "2016-10-28" }
{ "index": {}}
{ "price" : 2000, "color" : "红色", "brand" : "长虹", "sold_date" : "2016-11-05" }
{ "index": {}}
{ "price" : 3000, "color" : "绿色", "brand" : "小米", "sold_date" : "2016-05-18" }
{ "index": {}}
{ "price" : 1500, "color" : "蓝色", "brand" : "TCL", "sold_date" : "2016-07-02" }
{ "index": {}}
{ "price" : 1200, "color" : "绿色", "brand" : "TCL", "sold_date" : "2016-08-19" }
{ "index": {}}
{ "price" : 2000, "color" : "红色", "brand" : "长虹", "sold_date" : "2016-11-05" }
{ "index": {}}
{ "price" : 8000, "color" : "红色", "brand" : "三星", "sold_date" : "2017-01-01" }
{ "index": {}}
{ "price" : 2500, "color" : "蓝色", "brand" : "小米", "sold_date" : "2017-02-12" }
三、实战
3.1 metric:按数量分组
我们需要统计哪种颜色的电视机销量最高:
GET /tvs/_search
{
"size" : 0,
"aggs" : {
"popular_colors" : {
"terms" : {
"field" : "color"
}
}
}
}
查询请求的各个关键字含义如下:
- size:只获取聚合结果,而不需要返回执行聚合的那些原始数据;
- aggs:固定语法,表示要对一份数据执行分组聚合操作;
- popular_colors:每个aggs的名字,自定义;
- terms:根据字段值进行分组;
- field:进行分组的字段。
上述请求的返回结果如下:
{
"took" : 7,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 8,
"relation" : "eq"
},
"max_score" : null,
"hits" : [ ]
},
"aggregations" : {
"popular_colors" : {
"doc_count_error_upper_bound" : 0,
"sum_other_doc_count" : 0,
"buckets" : [
{
"key" : "红色",
"doc_count" : 4
},
{
"key" : "绿色",
"doc_count" : 2
},
{
"key" : "蓝色",
"doc_count" : 2
}
]
}
}
}
我们来看下返回结果中的一些核心关键字的含义:
- hits.hits:我们在请求中指定了size=0,所以hits.hits就是空的,否则会把执行聚合的那些原始数据返回;
- aggregations:聚合结果;
- popular_color:自定义的聚合名称;
- buckets:根据我们指定的field划分出的buckets;
- key:field的值
- doc_count:这个bucket分组内的doc条数
按数量分组其实并不算是一个metric操作,它是Elasticsearch对聚合分析的一种默认操作,利用term实现。
3.2 metric:统计平均值
这一节,我们来学习第一个metric操作——统计平均值。假设我们需要统计每种颜色电视机的平均价格:
GET /tvs/_search
{
"size" : 0,
"aggs": {
"colors": {
"terms": {
"field": "color"
},
"aggs": {
"avg_price": {
"avg": {
"field": "price"
}
}
}
}
}
}
上述请求,我们嵌套了一个”aggs“,这个”aggs“和“terms”平级,会对每个bucket执行一次metric操作:
"aggs": {
"avg_price": {
"avg": {
"field": "price"
}
}
}
返回结果如下:
{
"took" : 12,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 8,
"relation" : "eq"
},
"max_score" : null,
"hits" : [ ]
},
"aggregations" : {
"colors" : {
"doc_count_error_upper_bound" : 0,
"sum_other_doc_count" : 0,
"buckets" : [
{
"key" : "红色",
"doc_count" : 4,
"avg_price" : {
"value" : 3250.0
}
},
{
"key" : "绿色",
"doc_count" : 2,
"avg_price" : {
"value" : 2100.0
}
},
{
"key" : "蓝色",
"doc_count" : 2,
"avg_price" : {
"value" : 2000.0
}
}
]
}
}
}
可以看到,每个bucket内部多了”avg_price“,其value就是我们的metric计算的结果——每个bucket中的所有doc的price字段值的平均值。
3.3 下钻分析
所谓下钻分析,就是对每个bucket再进行分组,然后对每个最小粒度的分组再执行聚合分析操作。比如,我们已经按照颜色对电视机进行分组了,但是还想统计下每种颜色下的各个品牌的电视机平均价格:
GET /tvs/_search
{
"size": 0,
"aggs": {
"group_by_color": {
"terms": {
"field": "color"
},
"aggs": {
"color_avg_price": {
"avg": {
"field": "price"
}
},
"group_by_brand": {
"terms": {
"field": "brand"
},
"aggs": {
"brand_avg_price": {
"avg": {
"field": "price"
}
}
}
}
}
}
}
}
可以看到,上述请求在最内部又嵌套了一个"group_by_brand",按照band字段进行分组,然后求品牌的平均价格:
"group_by_brand": {
"terms": {
"field": "brand"
},
"aggs": {
"brand_avg_price": {
"avg": {
"field": "price"
}
}
}
}
返回结果如下:
{
"took" : 54,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 8,
"relation" : "eq"
},
"max_score" : null,
"hits" : [ ]
},
"aggregations" : {
"group_by_color" : {
"doc_count_error_upper_bound" : 0,
"sum_other_doc_count" : 0,
"buckets" : [
{
"key" : "红色",
"doc_count" : 4,
"color_avg_price" : {
"value" : 3250.0
},
"group_by_brand" : {
"doc_count_error_upper_bound" : 0,
"sum_other_doc_count" : 0,
"buckets" : [
{
"key" : "长虹",
"doc_count" : 3,
"brand_avg_price" : {
"value" : 1666.6666666666667
}
},
{
"key" : "三星",
"doc_count" : 1,
"brand_avg_price" : {
"value" : 8000.0
}
}
]
}
},
{
"key" : "绿色",
"doc_count" : 2,
"color_avg_price" : {
"value" : 2100.0
},
"group_by_brand" : {
"doc_count_error_upper_bound" : 0,
"sum_other_doc_count" : 0,
"buckets" : [
{
"key" : "TCL",
"doc_count" : 1,
"brand_avg_price" : {
"value" : 1200.0
}
},
{
"key" : "小米",
"doc_count" : 1,
"brand_avg_price" : {
"value" : 3000.0
}
}
]
}
},
{
"key" : "蓝色",
"doc_count" : 2,
"color_avg_price" : {
"value" : 2000.0
},
"group_by_brand" : {
"doc_count_error_upper_bound" : 0,
"sum_other_doc_count" : 0,
"buckets" : [
{
"key" : "TCL",
"doc_count" : 1,
"brand_avg_price" : {
"value" : 1500.0
}
},
{
"key" : "小米",
"doc_count" : 1,
"brand_avg_price" : {
"value" : 2500.0
}
}
]
}
}
]
}
}
}
3.4 metric:统计极值
我们现在需要统计每种颜色的电视机的最高价和最低价:
GET /tvs/_search
{
"size" : 0,
"aggs": {
"colors": {
"terms": {
"field": "color"
},
"aggs": {
"min_price" : { "min": { "field": "price"} },
"max_price" : { "max": { "field": "price"} }
}
}
}
}
返回结果就不贴了,通过上述的几个示例我们可以看到,90%的常见数据分析操作,无非就是count、avg、max、min、sum之类的metric操作。
四、总结
本章,我介绍了Elasticsearch中的聚合分析操作,聚合分析的核心就是先分组,然后对组内的记录执行metric操作,也可以分组之后再细粒度分组。常用的metric操作无非就是些求总数、平均值、极值之类的操作。
感谢赞赏~
- 本文标签: Elasticsearch
- 版权声明: 本站原创文章,于2019年05月09日由ressmix发布,作者保留所有权利,未经作者允许,禁止转载和演绎!