es7.x(10)aggs聚合查询

  1. ES聚合查询流程
  2. 核心概念
    2.1 桶
    2.2 指标
  3. ES聚合查询的语法
    3.1 聚合查询的size语法
  4. 指标聚合
    4.1 value count
    4.2 Cardinality
    4.3 avg sum max min
    4.4 综合例子
  5. 分组聚合查询(bucket)
    5.1 Terms聚合
    5.2 Histogram聚合
    5.3 Date histogram聚合
    5.4 Range聚合
    5.5 混合使用
  6. 多桶排序
    6.1 多桶排序
    --6.1.1 内置排序
    --6.1.2 按度量排序
    6.2 限制返回桶的数量
    推荐阅读

ES的聚合查询,类似SQL中sum/avg/count/group by分组查询,主要用于统计分析

1. ES聚合查询流程

ES聚合查询类似SQL的group by,一般统计分析主要分为两个步骤:

  1. group by分组
  2. 组内聚合

对查询的数据一般先进行分组,可以设置分组条件。然后将组内的数据进行聚合统计。

2. 核心概念

2.1 桶

满足特定条件的文档集合,叫做桶。

桶的就是一组数据的集合,数据分组后,得到一组组的数据,就是一组组的桶。

桶等同于组,分桶和分组是一个意思。

ES中桶聚合,指的就是先对数据进行分组,ES支持多种分组条件。

2.2 指标

指标指的是对文档进行统计计算的方式,又称指标聚合。

桶内聚合:就是对数据先进行分组(分桶),然后对每一个桶内的数据进行指标聚合。

常见的指标有:sum/count/max/min等统计函数。

3. ES聚合查询的语法

{
  "aggregations" : {  (1)
    "" : {  (2)
        "" : { (3)
               (4)
        }
        [,"aggregations" : { []+ } ]? // 嵌套聚合查询,支持多层嵌套
    }
    [,"" : { ... } ]* // 多个聚合查询,每个聚合查询取不同的名字
  }
}

(1) aggregations :代表聚合查询语句,可以简写为aggs;
(2):代表一个聚合计算的铭记,可以随意命名,因为ES支持一次进行多次的统计分析查询,后面需要通过这个名字在查询结果中找到我们想要的结果;
(3):聚合类型,代表我们想要怎么统计数据。主要有两大类的聚合类型:桶聚合和指标聚合,这两类又包括多种聚合类型,例如:指标聚合:sum/count。桶聚合:terms、Date、histogram等。
(4):聚合类型的参数,选择不同的聚合类型,又不同的参数。

es7.x(10)aggs聚合查询_第1张图片
image.png

3.1 聚合查询的size语法

size=0代表不需要返回query查询结果,仅仅返回aggs统计结果

GET test_len/_search
{
  "size": 0, 
  "aggs": {
    "prices": {
      "date_histogram": {
        "field": "p_date",
        "calendar_interval":"month",
        "format": "yyyy-MM-dd"
      }
    }
  }
}

4. 指标聚合

ES指标聚合,就是类型SQL的统计函数,指标聚合可以单独使用,也可以和桶聚合一起使用。

常用的统计函数:

  • value count:统计总数;
  • Cardinality:类似SQL的count(DISTINCT 字段), 统计不重复的数据总数
  • avg:平均值
  • sum:求和
  • max:最大值
  • min:最小值

4.1 value count

值聚合,主要用于统计文档总数。

es7.x(10)aggs聚合查询_第2张图片
image.png
es7.x(10)aggs聚合查询_第3张图片
image.png

如上图所示:得到的总数为2个文档。

GET test_len/_search
{
  "aggs": {
    "price_count": {   //名字随便起,聚合查询的名字
      "value_count": {    //聚合查询的类型
        "field": "price"  //计算price这个字段的总数
      }
    }
  }
}

4.2 Cardinality

基数聚合,也是用于统计文档的总数,跟value Count的区别是:基数聚合会去重,不会统计重复的值,类似SQL的count(distinct 字段)的用法。

注意:前面提到基数聚合的作用等价于SQL的count(DISTINCT 字段)的用法,其实不太准确,因为SQL的count统计结果是精确统计不会丢失精度,但是ES的cardinality基数聚合统计的总数是一个近似值,会有一定的误差,这么做的目的是为了性能,因为在海量的数据中精确统计总数是非常消耗性能的,但是很多业务场景不需要精确的结果,只要近似值,例如:统计网站一天的访问量,有点误差没关系。

4.3 avg sum max min

avg:求平均值
sum:求和
max:求最大值
min:求最小值

4.4 综合例子

前面的例子,仅仅介绍聚合指标的单独使用的情况,实际应用中经常先通过query查询,搜索索引中的数据,然后对query查询结果进行统计分析。

GET test_len/_search
{
  "query": {
    "term": {
      "p_type": {
        "value": "vip"
      }
    }
  },
  "aggs": {
    "sum_price": {
      "sum": {
        "field": "price" 
      }
    },
    "min_price":{
      "min": {
        "field": "price"
      }
    }
  }
}
es7.x(10)aggs聚合查询_第4张图片
image.png

5. 分组聚合查询(bucket)

Elasticsearch桶聚合,目的就是数据分组,先将数据按指定的条件分成多个组,然后对每一个组进行统计。 组的概念跟桶是等同的,在ES中统一使用桶(bucket)这个术语。

ES桶聚合的作用跟sql的group by作用是一样的,区别是ES支持更加强大的数据分组能力,SQL只能根据字段的唯一值进行分组,分组的数量跟字段的唯一值的数量相等,例如: group by 店铺id, 去掉重复的店铺ID后,有多少个店铺就有多少个分组。

ES常用的桶聚合如下:

  • terms聚合:类似sql的group by,根据字段唯一值分组;
  • Histogram(柱状图, [ˈhɪstəɡræm])聚合:根据数组间隔分组,例如:价格100间隔分组,0,100,200等等;
  • Date histogram聚合:根据时间间隔分组,例如:按月、天、小时分组;
  • Range聚合:按数值范围,例如0-150、150-200一组,200-500一组。

桶聚合一般不单独使用,都是配合指标聚合一起使用,对数据分组之后肯定要统计桶内数据,在ES中如果没有明确指定指标聚合,默认使用Value Count指标聚合,统计桶内文档总数。

5.1 Terms聚合

terms聚合的作用跟sql中的group by作用一致,都是根据字段唯一值对数据进行分组(分桶),字段值相等的文档都分到同一个桶内。

es7.x(10)aggs聚合查询_第5张图片
image.png

5.2 Histogram聚合

histogram(直方图)聚合,只要根据数值间隔分组,使用histogram聚合分组统计结果,通常用在绘制条形图报表。

POST test_len/_search?size=0
{
    "aggs" : {
        "prices" : { // 聚合查询名字,随便取一个
            "histogram" : { // 聚合类型为:histogram
                "field" : "price", // 根据price字段分桶
                "interval" : 50 // 分桶的间隔为50,意思就是price字段值按50间隔分组
            }
        }
    }
}
es7.x(10)aggs聚合查询_第6张图片
image.png

5.3 Date histogram聚合

类似histogram聚合,区别是Date histogram可以很好的处理时间类型字段,主要用于根据时间、日期分桶的场景。

POST /sales/_search?size=0
{
    "aggs" : {
        "sales_over_time" : { // 聚合查询名字,随便取一个
            "date_histogram" : { // 聚合类型为: date_histogram
                "field" : "date", // 根据date字段分组
                "calendar_interval" : "month", // 分组间隔:month代表每月、支持minute(每分钟)、hour(每小时)、day(每天)、week(每周)、year(每年)
                "format" : "yyyy-MM-dd" // 设置返回结果中桶key的时间格式
            }
        }
    }
}

返回结果:

{
    ...
    "aggregations": {
        "sales_over_time": { // 聚合查询名字
            "buckets": [ // 桶聚合结果
                {
                    "key_as_string": "2015-01-01", // 每个桶key的字符串标识,格式由format指定
                    "key": 1420070400000, // key的具体字段值
                    "doc_count": 3 // 默认按Value Count指标聚合,统计桶内文档总数
                },
                {
                    "key_as_string": "2015-02-01",
                    "key": 1422748800000,
                    "doc_count": 2
                },
                {
                    "key_as_string": "2015-03-01",
                    "key": 1425168000000,
                    "doc_count": 2
                }
            ]
        }
    }
}

5.4 Range聚合

GET /_search
{
    "aggs" : {
        "price_ranges" : { // 聚合查询名字,随便取一个
            "range" : { // 聚合类型为: range
                "field" : "price", // 根据price字段分桶
                "ranges" : [ // 范围配置
                    { "to" : 100.0 }, // 意思就是 price < 100的文档归类到一个桶
                    { "from" : 100.0, "to" : 200.0 }, // price>=100 and price<200的文档归类到一个桶
                    { "from" : 200.0 } // price>=200的文档归类到一个桶
                ]
            }
        }
    }
}

返回结果:

{
    ...
    "aggregations": {
        "price_ranges" : { // 聚合查询名字
            "buckets": [ // 桶聚合结果
                {
                    "key": "*-100.0", // key可以表达分桶的范围
                    "to": 100.0, // 结束值
                    "doc_count": 2 // 默认按Value Count指标聚合,统计桶内文档总数
                },
                {
                    "key": "100.0-200.0",
                    "from": 100.0, // 起始值
                    "to": 200.0, // 结束值
                    "doc_count": 2
                },
                {
                    "key": "200.0-*",
                    "from": 200.0,
                    "doc_count": 3
                }
            ]
        }
    }
}

可以发现,range分桶,默认key的值不友好。尤其是开发的时候,不知道key是什么样子,处理比较麻烦,可以为每一个分桶指定一个有意义的名字。

GET /_search
{
    "aggs" : {
        "price_ranges" : {
            "range" : {
                "field" : "price",
                "keyed" : true,
                "ranges" : [
                    // 通过key参数,配置每一个分桶的名字
                    { "key" : "cheap", "to" : 100 },
                    { "key" : "average", "from" : 100, "to" : 200 },
                    { "key" : "expensive", "from" : 200 }
                ]
            }
        }
    }
}
es7.x(10)aggs聚合查询_第7张图片
image.png

5.5 混合使用

实际开发中,经常需要配合query语句,先搜索目标文档,然后使用aggs聚合语句对搜索结果进行统计分析。

聚合查询支持多层嵌套。

GET /cars/_search
{
    "size": 0, // size=0代表不需要返回query查询结果,仅仅返回aggs统计结果
    "query" : { // 设置查询语句,先赛选文档
        "match" : {
            "make" : "ford"
        }
    },
    "aggs" : { // 然后对query搜索的结果,进行统计
        "colors" : { // 聚合查询名字
            "terms" : { // 聚合类型为:terms 先分桶
              "field" : "color"
            },
            "aggs": { // 通过嵌套聚合查询,设置桶内指标聚合条件
              "avg_price": { // 聚合查询名字
                "avg": { // 聚合类型为: avg指标聚合
                  "field": "price" // 根据price字段计算平均值
                }
              },
              "sum_price": { // 聚合查询名字
                "sum": { // 聚合类型为: sum指标聚合
                  "field": "price" // 根据price字段求和
                }
              }
            }
        }
    }
}

6. 多桶排序

类似terms、histogram、date_histogram这类桶聚合都会动态生成多个桶,如果生成的桶特别多,我们如何确定这些桶的排序顺序,如何限制返回桶的数量。

6.1 多桶排序

默认情况下,ES会根据doc_count文档总数,降序排序。

ES桶聚合支持两种方式排序:

  • 内置排序;
  • 按度量指标排序;

6.1.1 内置排序

内置排序参数:

  • _count :按文档数排序,对terms、histogram、date_histogram有效;
  • _term:按次项的字符串值的字母顺序排序,只在terms内使用;
  • _key:按每个桶的键值数值排序,仅对histogram和date_histogram有效;
GET /cars/_search
{
    "size" : 0,
    "aggs" : {
        "colors" : { // 聚合查询名字,随便取一个
            "terms" : { // 聚合类型为: terms
              "field" : "color", 
              "order": { // 设置排序参数
                "_count" : "asc"  // 根据_count排序,asc升序,desc降序
              }
            }
        }
    }
}

6.1.2 按度量排序

通常情况下,我们根据桶聚合分桶后,都会对桶内进行多个维度的指标聚合,所以我们也可以根据桶内指标聚合的结果进行排序。

GET /cars/_search
{
    "size" : 0,
    "aggs" : {
        "colors" : { // 聚合查询名字
            "terms" : { // 聚合类型: terms,先分桶
              "field" : "color", // 分桶字段为color
              "order": { // 设置排序参数
                "avg_price" : "asc"  // 根据avg_price指标聚合结果,升序排序。
              }
            },
            "aggs": { // 嵌套聚合查询,设置桶内聚合指标
                "avg_price": { // 聚合查询名字,前面排序引用的就是这个名字
                    "avg": {"field": "price"} // 计算price字段平均值
                }
            }
        }
    }
}

6.2 限制返回桶的数量

如果分桶数量太多,可以通过给桶聚合增加一个size参数限制返回桶的数量。

GET /_search
{
    "aggs" : {
        "products" : { // 聚合查询名字
            "terms" : { // 聚合类型为: terms
                "field" : "product", // 根据product字段分桶
                "size" : 5 // 限制最多返回5个桶
            }
        }
    }
}

推荐阅读

Elasticsearch笔记(七):聚合查询

Elasticsearch 聚合查询(aggs)基本概念

你可能感兴趣的:(es7.x(10)aggs聚合查询)