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
            }
        }
    }

你可能感兴趣的:(Elasticsearch之聚合查询)