欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Elasticsearch的聚合查询

程序员文章站 2022-07-09 15:36:49
...

Elasticsearch的聚合

Elasticsearch的聚合涉及到2个核心的概念BucketsMetricsMetrics相当于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节点即可。这是对查询结果的过滤,还有过滤桶。