美文网首页mysql
Elasticsearch之聚合查询

Elasticsearch之聚合查询

作者: 冰河winner | 来源:发表于2020-09-02 17:08 被阅读0次

    在数据库领域,借助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
                }
            }
        }
    

    相关文章

      网友评论

        本文标题:Elasticsearch之聚合查询

        本文链接:https://www.haomeiwen.com/subject/dlpwsktx.html