聚集查询(Aggregation)提供了针对多条文档的统计运算功能,它不是针对文档本身内容的检索,而是要将它们聚合到一起运算某些方面的特征值。

聚集查询与SQL语言中的聚集函数非常像,聚集函数在Elasticsearch中相当于是聚集查询的一种聚集类型。比如在SQL中的avg函数用于求字段平均值,而在Elasticsearch中要实现相同的功能可以使用avg聚集类型。

聚集查询的格式

聚集查询也是通过_search接口执行,只是在执行聚集查询时使用的参数是aggregations或aggs。所以_search接口可以执行两种类型的查询:

  1. 通过query参数执行DSL
  2. 通过aggregations执行聚集查询

这两种查询方式还可以放在一起使用, 执行逻辑是先通过DSL检索满足查询条件的文档,然后再使用聚集查询对DSL检索结果做聚集运算。

聚集查询有着比较规整的请求结构,具体格式如下:

"aggregations/aggs" : {
"<聚集名称>":{
"<聚集类型>":{
<聚集体>
}
………
[,"aggregations/aggs" : ( [ <子聚集>]+ ) ]
}
[,"<聚集名称>”: (...) ]*
}

aggregations和aggs都是_search的参数,其中aggs是agregations的简写。每一个聚集查询都需要定义一个聚集名称,并归属于种聚集类型。聚集名称是用户自定义的, 而聚集类型则是由Elasticsearch预先定义好。聚集名称会在返回结果中标识聚集结果,而聚集类型则决定了聚集将如何运算。比如前面提到的avg就是一种聚集类型。这里要特别强调的是,聚集中可以再包含子聚集。子聚集位于父聚集的名称中,与聚集类型同级,所以子聚集的运算都是在父聚集的环境中运算。

Eaticsarch对子聚集的深度没有限制,所以理论上说可以包含无限深度的子聚集。

聚集查询的类型

聚集类型总体上被分为四种大类型:

  • 指标聚集(Metrics Aggregation):根据文档字段所包含的值运算某些统计特征值,如平均值、总和等,它们的结果一般都包含一个或多个数值,前面提到的avg聚集就是指标聚集的一种。
  • 桶型聚集(Bucket Aggregation):根据一定的分组标准将文档归到不同的组中,这些分组在Elasticsearch 中被称为桶(Bucket),桶型聚集与SQL中group by的作用类似,一般会与指标聚集嵌套使用。
  • 管道聚集(Pipeline Aggregation):可以理解为聚集结果的再聚集,它一般以另一个聚集结果作为输人,然后在此基础上再做聚集。
  • 矩阵聚集(Matrix Aggregation):是Elasticsearch中的新功能,由于是针对多字段做多种运算,所以形成的结果类似于矩阵。

指标聚集

指标聚集是根据文档中某一字段做聚集运算,比如计算所有产品销量总和、平均值等等。指标聚集的结果可能是单个值,这种指标聚集称为单值指标聚集;也可能是多个值,称为多值指标聚集。

平均值聚集

平均值聚集是根据文档中数值类型字段计算平均值的聚集查询,包括avg聚集和weighted_avg聚集两种类型。

avg聚集直接取字段值后计算平均值,而weighted_avg聚集则会在计算平均值时添加不同的权重。

avg聚集计算平均值,例如计算航班的平均延误时间:

POST kibana_sample_data_flights/_search?filter_path=aggregations
{
  "aggs": {
    "avg_aggs": {
      "avg": {
        "field": "FlightDelayMin"
      }
    }
  }
}

使用了请求参数fiter_path将返回结果的其他字段过滤掉了,否则查询的结果中将包含kibana_sample_data_flights索引中的文档。加了filter_path之后返果为:

{
  "aggregations" : {
    "avg_aggs" : {
      "value" : 47.33517114633586
    }
  }
}

在返回结果中,aggregations是关键字,代表这是聚集查询的结果。其中的delay_avg则是在聚集查询中定义的聚集名称,value是聚集运算的结果。在示例中运算航班延误时间时会将所有文档都包含进来做计算,如果只想其中一部分文档参与运算则可以使用query参数以DSL的形式定义查询条件。

例如只计算了飞往中国的航班平均延误时间:

POST kibana_sample_data_flights/_search?filter_path=aggregations
{
  "query": {
    "match": {
      "DestCountry": "CN"
    }
  }, 
  "aggs": {
    "avg_aggs": {
      "avg": {
        "field": "FlightDelayMin"
      }
    }
  }
}
输出结果:
{
  "aggregations" : {
    "avg_aggs" : {
      "value" : 44.73996350364963
    }
  }
}

在示例中请求_search接口时,同时使用了query与aggs参数。在执行检索时会先通过query条件过滤文档,然后再在符合条件的文档中运算平均值聚集。

加权平均值聚集

weighted_avg无非就是根据某些条件对进行聚集的数据进行加权运算,和avg聚集没有本质差别。

POST kibana_sample_data_flights/_search?filter_path=aggregations
{
  "query": {
    "match": {
      "DestCountry": "CN"
    }
  },
  "aggs": {
    "avg_aggs": {
      "weighted_avg": {
        "value": {
          "field": "FlightDelayMin"
        },
        "weight": {
          "field": "DistanceKilometers"
          }
      }
    }
  }
}
输出结果:
{
  "aggregations" : {
    "avg_aggs" : {
      "value" : 42.29622477052496
    }
  }
}

计数聚集

计数聚集用于统计字段值的数量,类似于SQL中的count。

POST kibana_sample_data_flights/_search?filter_path=aggregations
{
  "aggs": {
    "count": {
      "cardinality": {
        "field": "DestCountry"
      }
    },
    "distinct_count": {
      "value_count": {
        "field": "DestCountry"
      }
    }
  }
}
输出结果:
{
  "aggregations" : {
    "count" : {
      "value" : 32
    },
    "distinct_count" : {
      "value" : 13059
    }
  }
}

value_count聚集用于统计字段中值的总数,而cardinality用于统计不重复值的总数。

cardinality聚集的算法使用极小内存实现统计结果的基本准确。所以cardinality在数据量极大的情况下是不能保证完全准确的。

极值聚集

极值聚集是在文档中提取某一字段最大值或最小值的聚集,包括max聚集和min聚集。

例如:

POST kibana_sample_data_flights/_search?filter_path=aggregations
{
  "aggs": {
    "min_price": {
      "min": {
        "field": "AvgTicketPrice"
      }
    },
    "max_price": {
      "max": {
        "field": "AvgTicketPrice"
      }
    }
  }
}
输出结果:
{
  "aggregations" : {
    "max_price" : {
      "value" : 1199.72900390625
    },
    "min_price" : {
      "value" : 100.0205307006836
    }
  }
}

和聚集

和聚集就是求某个字段的和,类似于SQL中的sum。

POST kibana_sample_data_flights/_search?filter_path=aggregations
{
  "query": {
    "match": {
      "DestCountry": "CN"
    }
  },
  "aggs": {
    "sum_aggs": {
      "sum": {
        "field": "FlightDelayMin"
      }
    }
  }
}
输出结果:
{
  "aggregations" : {
    "sum_aggs" : {
      "value" : 49035.0
    }
  }
}

统计聚集

统计聚集是一个多值指标聚集,也就是返回结果中会包含多个值,都是一些与统计相关的数据。统计聚集包含stats聚集和extended_stats聚集两种,前者返回的统计数据是一些比较基本的数值,而后者则包含一些比较专业的统计数值。

stats聚集

stats聚集返回结果中包括字段的最小值(min)、最大值(max)、总和(sum)、计数(count) 及平均值(avg) 五项内容。

例如,对机票价格做统计:

POST kibana_sample_data_flights/_search?filter_path=aggregations
{
  "aggs": {
    "price_stats": {
      "stats": {
        "field": "AvgTicketPrice"
      }
    }
  }
}
输出结果:
{
  "aggregations" : {
    "price_stats" : {
      "count" : 13059,
      "min" : 100.0205307006836,
      "max" : 1199.72900390625,
      "avg" : 628.2536888148849,
      "sum" : 8204364.922233582
    }
  }
}

extended_stats聚集

extended_stats聚集增加了几项统计数据,这包括平方和、方差、标准方差和标准方差偏移量。从使用的角度来看,extended_stats聚集与stats聚集完全相同,只是聚集类型不同。

POST kibana_sample_data_flights/_search?filter_path=aggregations
{
  "aggs": {
    "price_stats": {
      "extended_stats": {
        "field": "AvgTicketPrice"
      }
    }
  }
}
输出结果:
{
  "aggregations" : {
    "price_stats" : {
      "count" : 13059,
      "min" : 100.0205307006836,
      "max" : 1199.72900390625,
      "avg" : 628.2536888148849,
      "sum" : 8204364.922233582,
      "sum_of_squares" : 6.081113366492191E9,
      "variance" : 70961.85310632498,
      "std_deviation" : 266.38666090163935,
      "std_deviation_bounds" : {
        "upper" : 1161.0270106181636,
        "lower" : 95.48036701160618
      }
    }
  }
}

百分位聚集

百分位聚集根据文档字段值统计字段值按百分比的分布情况,包括pecrentiles聚集和percentile_ranks两种。前者统计的是百分比与值的对应关系,而后者正好相反统计值与百分比的对应关系。

POST kibana_sample_data_flights/_search?filter_path=aggregations
{
  "aggs": {
    "price_percentiles": {
      "percentiles": {
        "field": "AvgTicketPrice",
        "percents": [
          25,
          50,
          75,
          100
        ]
      }
    },
    "price_percentiles_rank": {
      "percentile_ranks": {
        "field": "AvgTicketPrice",
        "values": [
          600,
          1200
        ]
      }
    }
  }
}
输出结果:
{
  "aggregations" : {
    "price_percentiles_rank" : {
      "values" : {
        "600.0" : 45.41644793599837,
        "1200.0" : 100.0
      }
    },
    "price_percentiles" : {
      "values" : {
        "25.0" : 410.01103863927534,
        "50.0" : 640.3872852064159,
        "75.0" : 842.2604821407433,
        "100.0" : 1199.72900390625
      }
    }
  }
}

pecrentiles聚集通过pecrents参数设置组百分比,然后按值由小到大的顺序划分不同区间,每个区间对应一个百分比。percentile_ranks聚集则通过value参数设置组值,然后根据这些值分别计算落在不同值区间的百分比。

以示例返回的结果为例:在pecrentiles返回结果price_percentiles中,"25.0" : 410.01103863927534 代表的含义是25%的机票价格都小于410.01103863927534,其他以此类推。在percentile_ranks返回结果price_percentiles_rank中, "600.0" : 45.41644793599837代表的含义是600.0以下的机票占总机票价格的百分比为
45.41644793599837%。