类型
ES 中聚合的类型主要有以下 3 种:
- Metric Aggregations: 提供求 sum(求总和)、average(求平均数) 等数学运算,可以对字段进行统计分析。
- Bucket Aggregations:分桶类型,对满足特定条件的文档进行分组,例如将 A 出版社的书本分为一组,将 B 出版社的书本分为一组,类似于 SQL 里的 Group By 功能。
- Pipeline Aggregations:对其他聚合输出的结果进行再次聚合。
- Matrⅸ,矩阵分析类型
ES 的聚合可以进行多种组合来构建的统计查询,从而解决复杂的统计分析的需求
简介
聚合分析是数据库中重要的功能特性,完成对一个查询的数据集中数据的聚合计算,如:找出某字段 (或计算表达式的结果)的最大值、最小值,计算和、平均值等
- 聚合的两个主要的概念,分别是 桶 和 指标
- 桶(Buckets) : 满足特定条件的文档的集合
- 当聚合开始被执行,每个文档会决定符合哪个桶的条件,如果匹配到,文档将放入相应的桶并接着进行聚合操作
- 像是一个员工属于男性桶或者女性桶,日期2014-10-28属于十月桶,也属于2014年桶
- 桶可以被嵌套在其他桶里面
- 像是北京能放在中国桶裡,而中国桶能放在亚洲桶裡
- Elasticsearch提供了很多种类型的桶,像是时间、最受欢迎的词、年龄区间、地理位置桶等等,不过他们在根本上都是通过同样的原理进行操作,也就是基于条件来划分文档,一个文档只要符合条件,就可以加入那个桶,因此一个文档可以同时加入很多桶
- 当聚合开始被执行,每个文档会决定符合哪个桶的条件,如果匹配到,文档将放入相应的桶并接着进行聚合操作
- 指标(Metrics) : 对桶内的文档进行统计计算
- 桶能让我们划分文档到有意义的集合, 但是最终我们需要的是对这些桶内的文档进行一些指标的计算
- 指标通常是简单的数学运算(像是min、max、avg、sum),而这些是通过当前桶中的文档的值来计算的,利用指标能让你计算像平均薪资、最高出售价格、95%的查询延迟这样的数据
- 桶(Buckets) : 满足特定条件的文档的集合
aggs 聚合的模板
- 当query和aggs一起存在时,会先执行query的主查询,主查询query执行完后会搜出一批结果,而这些结果才会被拿去aggs拿去做聚合
- 另外要注意aggs后面会先接一层自定义的这个聚合的名字,然后才是接上要使用的聚合桶
- 如果有些情况不在意查询结果是什麽,而只在意aggs的结果,可以把size设为0,如此可以让返回的hits结果集是0,加快返回的速度
- 一个aggs裡可以有很多个聚合,每个聚合彼此间都是独立的,因此可以一个聚合拿来统计数量、一个聚合拿来分析数据、一个聚合拿来计算标准差…,让一次搜索就可以把想要做的事情一次做完
- aggs可以嵌套在其他的aggs裡面,而嵌套的桶能作用的文档集范围,是外层的桶所输出的结果集
语法:
在查询请求体中以aggregations节点按如下语法定义聚合分析:
aggregations 也可简写为 aggs
"aggregations": {"<aggregation_name>": { <!--聚合的名字 -->"<aggregation_type>" : { <!--聚合的类型 --><aggregation_body> <!--聚合体:对哪些字段进行聚合 -->}[,"meta" : { [<meta_data_body>] } ]? <!--元 -->[,"aggregations" : { [<sub_aggregation>]+ } ]? <!--在聚合里面在定义子聚合 -->}[, "<aggregation_name_2>": { ...}] * <!--聚合的名字 -->}
GET 127.0.0.1/mytest/doc/_search{"query": { ... },"size": 0, //建议设置为0,这样不会返回 _source"aggs": { //和query 同级别的关键词"custom_name1": { //aggs后面接著的是一个自定义的name,会从聚合结果中返回"桶": { ... } //再来才是接桶},"custom_name2": { //一个aggs裡可以有很多聚合,可以进行多个同级别的聚合查询"aggs_type": { //聚合的定义:聚合类型 + 聚合bodyaggs body}},"custom_name3": { //自定义的聚合名字,会从聚合结果中返回"桶": {.....},"aggs": { //aggs可以嵌套在别的aggs裡面, 子聚合"in_name": { //记得使用aggs需要先自定义一个name,会从聚合结果中返回"桶": { ... } //in_name的桶作用的文档是custom_name3的桶的结果}}}}}# 返回{"hits": {"total": 8,"max_score": 0,"hits": [] //因为size设为0,所以没有查询结果返回},"aggregations": {"custom_name1": {...},"custom_name2": {...},"custom_name3": {... ,"in_name": {....}}}}
聚合结果排序
对嵌套计算出的avg(balance),这里是average_balance,进行排序
GET /bank/_search{"size": 0,"aggs": {"group_by_state": {"terms": {"field": "state.keyword","order": {"average_balance": "desc"}},"aggs": {"average_balance": {"avg": {"field": "balance"}}}}}}
例子
准备数据
POST /test-agg-cars/_bulk{ "index": {}}{ "price" : 10000, "color" : "red", "make" : "honda", "sold" : "2014-10-28" }{ "index": {}}{ "price" : 20000, "color" : "red", "make" : "honda", "sold" : "2014-11-05" }{ "index": {}}{ "price" : 30000, "color" : "green", "make" : "ford", "sold" : "2014-05-18" }{ "index": {}}{ "price" : 15000, "color" : "blue", "make" : "toyota", "sold" : "2014-07-02" }{ "index": {}}{ "price" : 12000, "color" : "green", "make" : "toyota", "sold" : "2014-08-19" }{ "index": {}}{ "price" : 20000, "color" : "red", "make" : "honda", "sold" : "2014-11-05" }{ "index": {}}{ "price" : 80000, "color" : "red", "make" : "bmw", "sold" : "2014-01-01" }{ "index": {}}{ "price" : 25000, "color" : "blue", "make" : "ford", "sold" : "2014-02-12" }
标准的聚合
有了数据,开始构建我们的第一个聚合。汽车经销商可能会想知道哪个颜色的汽车销量最好,用聚合可以轻易得到结果,用 terms 桶操作:
- 聚合操作被置于顶层参数 aggs 之下(如果你愿意,完整形式 aggregations 同样有效)。
- 然后,可以为聚合指定一个我们想要名称,本例中是: popular_colors 。
最后,定义单个桶的类型 terms 。
GET /test-agg-cars/_search{"size" : 0,"aggs" : {"popular_colors" : {"terms" : {"field" : "color.keyword"}}}}

因为我们设置了 size 参数,所以不会有 hits 搜索结果返回。
- popular_colors 聚合是作为 aggregations 字段的一部分被返回的。
- 每个桶的 key 都与 color 字段里找到的唯一词对应。它总会包含 doc_count 字段,告诉我们包含该词项的文档数量。
- 每个桶的数量代表该颜色的文档数量。
多个聚合
同时计算两种桶的结果:对color和对makeGET /test-agg-cars/_search{"size" : 0,"aggs" : {"popular_colors" : {"terms" : {"field" : "color.keyword"}},"make_by" : {"terms" : {"field" : "make.keyword"}}}}
聚合的嵌套
这个新的聚合层让我们可以将 avg 度量嵌套置于 terms 桶内。实际上,这就为每个颜色生成了平均价格。GET /test-agg-cars/_search{"size" : 0,"aggs": {"colors": {"terms": {"field": "color.keyword"},"aggs": {"avg_price": {"avg": {"field": "price"}}}}}}

正如 颜色 的例子,我们需要给度量起一个名字( avg_price )这样可以稍后根据名字获取它的值。最后,我们指定度量本身( avg )以及我们想要计算平均值的字段( price )动态脚本的聚合
这个例子告诉你,ElasticSearch还支持一些基于脚本(生成运行时的字段)的复杂的动态聚合。GET /test-agg-cars/_search{"runtime_mappings": {"make.length": {"type": "long","script": "emit(doc['make.keyword'].value.length())"}},"size" : 0,"aggs": {"make_length": {"histogram": {"interval": 1,"field": "make.length"}}}}

