Elasticsearch的聚合查询
Elasticsearch的聚合
Elasticsearch的聚合涉及到2个核心的概念Buckets
和Metrics
,Metrics
相当于SQL查询中的COUNT SUM MAX MIN 之类的函数,Buckets
相当于分组GROUP BY。
Buckets
就相当于满足特定条件的文档的集合,Buckets
支持嵌套也就是说,聚合整个内蒙古地区居民的CPI,包头居民的CPI会被录入该Buckets
中,同时还需要计算整个中国的居民的CPI那么内蒙地区的CPI也会被录入中国这个维度的Buckets
,从这个例子就能知道,所谓的Buckets
就是基于条件来划分出不同的文档集合。
Metrics
就是在不同条件下划分出来的文档集合中做一些数学计算。比如求某个省最大的CPI,或者某个城市中Top5的CPI城市等等。
POST /my_index/commodity/
{
"id": "00000000000000000000000001212212",
"produceName": "Apple/苹果 iPhone 8",
"tags": [ "手机", "通讯设备" ],
"price":8788,
"info":{
"model":"金属"
},
"color": "土豪金",
"version": "128G",
"resolution": "1792*828",
"system": "ios系统",
"thickness": "薄(7mm-8.5mm)"
}
POST /my_index/commodity/
{
"id": "00000000000000000000000001212211",
"produceName": "华为(HUAWEI) 华为荣耀V20 手机",
"tags": [ "手机", "通讯设备" ],
"price":3488,
"info":{
"model":"金属"
},
"color": "魅海蓝",
"version": "6G+128G",
"resolution": "2310*1080",
"system": "安卓系统",
"thickness": "薄(7mm-8.5mm)"
}
POST /my_index/commodity/
{
"id": "00000000000000000000000001212210",
"produceName": "小米9 骁龙855 游戏手机",
"tags": [ "手机", "通讯设备" ],
"price":2999,
"info":{
"model":"金属"
},
"color": "深空灰",
"version": "128G",
"resolution": "1792*828",
"system": "安卓系统",
"thickness": "薄(7mm-8.5mm)"
}
先往我们的ES增加部分文档,用于聚合使用。首先我们根据操作系统来划分.这样我就能知道我所有商品ES中不同系统的文档个数。,这里指定"size": 0
的为了提升返回的性能,aggregation_system
是你指定的Buckets
的名称。terms
节点指定的就是SQL要分组的Column,在这里就引申为根据操作系统来划分文档集合。
http:x.x.x.x:9200//my_index/commodity/_search post
{
"size": 0,
"aggs": {
"aggregation_system": {
"terms": {
"field": "system.keyword"
}
}
}
}
result结果
{
"took": 19,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"failed": 0
},
"hits": {
"total": 3,
"max_score": 0,
"hits": []
},
"aggregations": {
"aggregation_system": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0,
"buckets": [{
"key": "安卓系统",
"doc_count": 2
},
{
"key": "ios系统",
"doc_count": 1
}
]
}
}
}
使用根据条件划分的集合去做指标的收集。收集不同系统的手机的平均价格。
http:x.x.x.x:9200//my_index/commodity/_search post
{
"size": 0,
"aggs": {
"aggregation_system": {
"terms": {
"field": "system.keyword"
},
"aggs": {
"avg_price": {
"avg": {
"field": "price"
}
}
}
}
}
}
result结果
{
"took": 19,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"failed": 0
},
"hits": {
"total": 3,
"max_score": 0,
"hits": []
},
"aggregations": {
"aggregation_system": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0,
"buckets": [{
"key": "安卓系统",
"doc_count": 2,
"avg_price": {
"value": 3243.5
}
},
{
"key": "ios系统",
"doc_count": 1,
"avg_price": {
"value": 8788
}
}
]
}
}
}
对应上述的DSL查询语法对应结构性数据库的查询如下
SELECT o.`system`,AVG(o.`price`),COUNT(*) FROM commodity o GROUP BY o.`system`
ES查询的聚合使用,只有在我们使用嵌套方案时,聚合的力量才能真正得以显现。此时我们结合上面的查询得知了,商品库中 不同系统的手机的数量,还有每种系统的平均价格,那我们还想知道每种系统不同的颜色和个数呢?不使用嵌套聚合的情况 我们可以试用应用层来处理,就是在service层发起另一次查询。ok,现在展示下嵌套聚合。
POST /my_index/commodity/_search
{
"size": 0,
"aggs": {
"aggregation_system": {
"terms": {
"field": "system.keyword"
},
"aggs": {
"avg_price": {
"avg": {
"field": "price"
}
},
"color": {
"terms": {
"field": "color.keyword"
}
}
}
}
}
}
result结果
{
"took": 19,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"failed": 0
},
"hits": {
"total": 3,
"max_score": 0,
"hits": []
},
"aggregations": {
"aggregation_system": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0,
"buckets": [{
"key": "安卓系统",
"doc_count": 2,
"avg_price": {
"value": 3243.5
},
"color": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0,
"buckets": [{
"key": "深空灰",
"doc_count": 1
}, {
"key": "魅海蓝",
"doc_count": 1
}]
}
},
{
"key": "ios系统",
"doc_count": 1,
"avg_price": {
"value": 8788
},
"color": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0,
"buckets": [{
"key": "土豪金",
"doc_count": 1
}]
}
}
]
}
}
}
注意我们在查询并没有指定查询的范围,所以 和 “查询所有文档” 是等价的。目前为止,我们已经可以熟练进行基本的聚合查询。聚合查询的高阶使用一般是配合数据可视化组件进行数据展示,例如Kibana的上的可视化展示,一般根据时间维度来进行聚合,可以提供展示直方图,折线图等图标,用作图标数据分析。此外实际的生产环境 我们肯定不是针对全表的扫描。而是根据一定的条件下的结果的聚合,例如是只查询发布时间范围在2018-2019年的手机的不同系统的手机的数量,还有每种系统的平均价格, 那么只需要在我们的聚合查询DSL语句中加入query
节点即可。这是对查询结果的过滤,还有过滤桶。
下一篇: 现在都在用的美图手机,壳也这么漂亮