mysql

Elasticsearch之聚合查询

2020-09-02  本文已影响0人  冰河winner

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

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

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

1、指标聚合

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

计算最大值:

{
    "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
            }
        }
    }
上一篇下一篇

猜你喜欢

热点阅读