Elasticsearch之聚合查询

在数据库领域,借助SQL我们可以获取表中的最大值(Max)、最小值(Min),还可以对数据进行分组(Group)。在ES中使用聚合(Aggregations)来实现类似的功能,而且比SQL更灵活、更强大。

ES 7中,将聚合分为四类:

  • 指标聚合(Metrics Aggregations): 一些数学运算,可以对文档字段进行统计分析,如计算最大值、最小值、平均值等,类似于SQL中的COUNT()SUM()MAX() 等统计方法
  • 桶聚合(Bucket Aggregations): 满足特定条件的文档分组,类似SQL中的GROUP BY
  • 管道聚合(Pipeline Aggregations): 管道分析类型,基于上一级的聚合分析结果进行在分析,工作在其他聚合计算结果而不是文档集合的聚合
  • 矩阵聚合(Matrix Aggregations): 操作多个字段并根据从请求的文档字段中提取的值生成矩阵结果

实际开发中,指标聚合和桶聚合用途很广泛,而管道聚合和矩阵聚合是带有实验性质的功能,很少使用。

1、指标聚合

按照输出结果的数量,指标聚合可以分为两类:

  • 单值分析,只输出一个分析结果:
    • Min:最小值
    • Max:最大值
    • Avg:平均值
    • Sum:累加值
    • Cardinality:不同数值的个数,相当于 SQL 中的 distinct
  • 多值分析,输出多个分析结果:
    • Stats:样的数据分析,可以一次性得到最大值、最小值、平均值、中值等数据
    • Extended Stats:是对 Stats 的扩展,包含了更多的统计数据,比如方差、标准差等
    • Percentiles:按从小到大累计每个值对应的文档数的占比,返回指定占比比例对应的值
    • Percentile Ranks:Percentiles是通过百分比求文档值,Percentile Ranks是通过文档值求百分比
    • Top Hits:一般用于分桶后获取桶内最匹配的顶部文档列表

计算最大值:

{
    "aggs":{
        "max_price":{
            "max":{
                "field":"price"
            }
        }
    }
}

可以与query结合使用,比如先过滤,再求和:

{
    "query":{
        "constant_score":{
            "filter":{
                "match":{
                    "type":"hat"
                }
            }
        }
    },
    "aggs":{
        "hat_prices":{
            "sum":{
                "field":"price"
            }
        }
    }
}

再来看一下Percentiles与Percentile Ranks的用法。假如有一批消费者数据,其中有一个字段记录了日均消费金额,现在想知道日均消费金额的分布占比情况:

{
    "size":0,
    "aggs":{
        "money_stat":{
            "percentiles":{
                "field":"money"
            }
        }
    }
}

返回结果:

{
    ...
   "aggregations": {
      "money_stat": {
         "values" : {
            "1.0": 5.0,
            "5.0": 25.0,
            "25.0": 165.0,
            "50.0": 445.0,
            "75.0": 725.0,
            "95.0": 945.0,
            "99.0": 985.0
         }
      }
   }
}

默认按照[ 1, 5, 25, 50, 75, 95, 99 ]来统计。

统计结果反映:1%的人消费金额在5元以内、5%的人消费金额在25元以内......95%的人消费金额在945元以内、99%的人消费金额在985元以内。

如果想知道日均消费金额在500以内以及600以内的人群占比是多少呢?可以使用Percentile Ranks来统计:

{
    "size":0,
    "aggs":{
        "money_ranks":{
            "percentile_ranks":{
                "field":"money",
                "values":[
                    500,
                    600
                ]
            }
        }
    }
}

返回结果:

{
    ...
   "aggregations": {
      "load_time_ranks": {
         "values" : {
            "500.0": 55.1,
            "600.0": 64.0
         }
      }
   }
}

统计结果反映:日均消费金额在500以内比为55.1%,日均消费金额在600以内的人群占比为64%。

结合桶聚合,还可以更复杂的统计,例如,根据工作类型分桶,然后按照性别分桶,计算每个桶中工资的最高的薪资:

{
    "size":0,
    "aggs":{
        "Job_gender_stats":{
            "terms":{
                "field":"job.keyword"
            },
            "aggs":{
                "gender_stats":{
                    "terms":{
                        "field":"gender"
                    },
                    "aggs":{
                        "salary_stats":{
                            "max":{
                                "field":"salary"
                            }
                        }
                    }
                }
            }
        }
    }
}

返回结果:

0.png

2、桶聚合

准备一组汽车销售数据用于测试,包含汽车的价格、颜色、品牌、销售时间:

POST /cars/_bulk
{ "index": {}}
{ "price" : 80000, "color" : "red", "brand" : "BMW", "sellTime" : "2014-01-28" }
{ "index": {}}
{ "price" : 85000, "color" : "green", "brand" : "BMW", "sellTime" : "2014-02-05" }
{ "index": {}}
{ "price" : 120000, "color" : "green", "brand" : "Mercedes", "sellTime" : "2014-03-18" }
{ "index": {}}
{ "price" : 105000, "color" : "blue", "brand" : "Mercedes", "sellTime" : "2014-04-02" }
{ "index": {}}
{ "price" : 72000, "color" : "green", "brand" : "Audi", "sellTime" : "2014-05-19" }
{ "index": {}}
{ "price" : 60000, "color" : "red", "brand" : "Audi", "sellTime" : "2014-06-05" }
{ "index": {}}
{ "price" : 40000, "color" : "red", "brand" : "Audi", "sellTime" : "2014-07-01" }
{ "index": {}}
{ "price" : 35000, "color" : "blue", "brand" : "Honda", "sellTime" : "2014-08-12" }
3、查看是否成功

2.1 Terms Aggregation

基于某个field,该 field 内的每一个唯一词元为一个桶,并计算每个桶内文档个数。默认返回顺序是按照文档个数多少排序。需要注意的是,生产环境中数据一般是分布在多个分片上,当不返回所有 buckets 时(由size控制),文档个数可能不准确

按照汽车品牌聚合,按照数量排序,只返回前三名:

{
    "aggs":{
        "genres":{
            "terms":{
                "field":"brand",
                "order":{
                    "_count":"asc"
                },
                "size":3
            }
        }
    }
}

返回结果:

1.png

2.2 Filter Aggregation

Terms Aggregation 的基础上进行了过滤,只对特定的值进行了聚合。

过滤获取品牌为BMW的桶,并求该桶平均值:

{
    "aggs":{
        "brands":{
            "filter":{
                "term":{
                    "brand":"BMW"
                }
            },
            "aggs":{
                "avg_price":{
                    "avg":{
                        "field":"price"
                    }
                }
            }
        }
    }
}

返回结果:

2.png

如果想要指定多个过滤条件,可以使用Filters Aggreagation:

{
    "size":0,
    "aggs":{
        "cars":{
            "filters":{
                "filters":{
                    "colorBucket":{
                        "match":{
                            "color":"red"
                        }
                    },
                    "brandBucket":{
                        "match":{
                            "brand":"Audi"
                        }
                    }
                }
            }
        }
    }
}

返回结果:

3.png

2.3 Histogram Aggreagtion

直方图聚合,与Terms聚合类似,都是数据分组,区别是Terms是按照Field的值分组,而Histogram可以按照指定的间隔对Field进行分组。

根据价格区间为10000分桶:

{
    "aggs":{
        "prices":{
            "histogram":{
                "field":"price",
                "interval":10000
            }
        }
    }
}

返回结果:

4.png

2.4 Range Aggregation

范围聚合,根据用户传递的范围参数作为桶,进行相应的聚合。在同一个请求中,可以传递多组范围,每组范围作为一个桶。

根据价格区间分桶:

{
    "aggs":{
        "price_ranges":{
            "range":{
                "field":"price",
                "ranges":[
                    {
                        "to":50000
                    },
                    {
                        "from":5000,
                        "to":80000
                    },
                    {
                        "from":80000
                    }
                ]
            }
        }
    }
}

返回结果:

5.png

2.5 Nested Aggregation

一个特殊的single bucket(单桶)聚合,可以聚合嵌套的文档
例如,假设我们有一个产品的索引,并且每个产品都包含一个分销商列表——每个产品都有自己的价格。映射可能是:

{
    ...

    "product" : {
        "properties" : {
            "resellers" : { #1
                "type" : "nested",
                "properties" : {
                    "name" : { "type" : "text" },
                    "price" : { "type" : "double" }
                }
            }
        }
    }
}

resellers是一个在product对象下保存嵌套文档的数组。

以下汇总将返回可以购买的最低价格产品:

{
    "query" : {
        "match" : { "name" : "led tv" }
    },
    "aggs" : {
        "resellers" : {
            "nested" : {
                "path" : "resellers"
            },
            "aggs" : {
                "min_price" : { "min" : { "field" : "resellers.price" } }
            }
        }
    }
}

如上所述,嵌套聚合需要顶层文档中嵌套文档的路径。 然后可以在这些嵌套文档上定义任何类型的聚合。

响应结果:

{
    "aggregations": {
        "resellers": {
            "min_price": {
                "value" : 350
            }
        }
    }
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,830评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,992评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,875评论 0 331
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,837评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,734评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,091评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,550评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,217评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,368评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,298评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,350评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,027评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,623评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,706评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,940评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,349评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,936评论 2 341