聚合框架帮助提供基于搜索查询的聚合数据。它基于称为聚合(aggregations)的简单构建块,可以组合这些构建块以构建复杂的数据摘要。

聚合可以看作是在一组文档上构建分析信息的工作单元。执行的上下文定义了该文档集是什么(例如,在搜索请求的已执行查询/过滤器的上下文中执行顶级聚合)。

有许多不同类型的聚合,每种类型都有自己的目的和输出。为了更好地理解这些类型,通常更容易将它们分为四大类:

Bucketing

构建bucket的聚合家族,其中每个bucket都与一个键和一个文档标准相关联。当执行聚合时,将对上下文中的每个文档评估所有bucket条件,当某个条件匹配时,该文档将被视为“落在”相关bucket中。在聚合过程结束时,我们将得到一个bucket列表—每个bucket都有一组“属于”它的文档。

Bucket聚合不像metrics聚合那样计算字段上的度量,而是创建文档的Bucket。每个bucket都与一个标准(取决于聚合类型)相关联,该标准确定当前上下文中的文档是否“落入”其中。换句话说,bucket有效地定义了文档集。除了bucket本身,bucket聚合还计算并返回“落入”每个bucket的文档数。

与 metrics 聚合相反,Bucket聚合可以容纳子聚合。这些子聚合将为其“父”bucket聚合创建的bucket进行聚合。

Metric

对一组文档进行跟踪和计算度量的聚合。

此聚合基于以某种方式从正在聚合的文档中提取的值来计算度量。值通常从文档的字段中提取(使用字段数据),但也可以使用脚本生成。

数值度量聚合是一种特殊类型的度量聚合,它输出数值。一些聚合输出单个数值度量(如avg),称为单值数值度量聚合,其他聚合生成多个度量(如stats),称为多值数值度量聚合。当单值和多值数字度量聚合用作某些存储桶聚合的直接子聚合时(某些存储桶聚合使我们能够根据每个存储桶中的数字度量对返回的存储桶进行排序),单值和多值数字度量聚合之间的区别就起到了一定的作用。

有不同的bucket聚合器,每个都有不同的“bucketing”策略。有的定义单个bucket,有的定义固定数量的多个bucket,有的在聚合过程中动态创建bucket。

单个响应中允许的最大存储桶数受名为search.max_bucket的动态群集设置的限制。它在默认情况下被禁用(-1),但是尝试返回超过10000个bucket(未来版本的默认值)的请求将记录一个弃用警告。但是,使用复合agg时,-1的处理方式不同。Elasticsearch会将软限制用作这些聚合的硬限制,并提出一个TooManyBucketsException,即试图创建太多的bucket。如果超过软限制,则必须小于或等于:[10000]。

Matrix

对多个字段进行操作并根据从请求的文档字段中提取的值生成矩阵结果的聚合族。与metric和bucket聚合不同,这个聚合系列还不支持脚本。

此功能是实验性的,在将来的版本中可能会完全更改或删除。Elastic将尽最大努力解决任何问题,但实验特性不受正式GA特性的支持SLA的约束。(7.13已经不存在了)

Pipeline

聚合其他聚合及其关联度量的输出

接下来是有趣的部分。由于每个bucket有效地定义了一个文档集(属于该bucket的所有文档),因此可以在bucket级别上潜在地关联聚合,这些聚合将在该bucket的上下文中执行。这就是聚合真正的威力所在:聚合可以嵌套!

Bucketing聚合可以有子聚合(Bucketing或metric)。将为其父聚合生成的bucket计算子聚合。嵌套聚合的级别/深度没有硬限制(可以将聚合嵌套在“父”聚合下,该聚合本身是另一个更高级别聚合的子聚合)。

构建聚合

以下代码段捕获了聚合的基本结构:

"aggregations" : {
    "<aggregation_name>" : {
        "<aggregation_type>" : {
            <aggregation_body>
        }
        [,"meta" : {  [<meta_data_body>] } ]?
        [,"aggregations" : { [<sub_aggregation>]+ } ]?
    }
    [,"<aggregation_name_2>" : { ... } ]*
}

JSON中的aggregations对象(也可以使用键aggs)保存要计算的聚合。每个聚合都与用户定义的逻辑名称相关联(例如,如果聚合计算平均价格,那么将其命名为avg_price是有意义的)。

这些逻辑名称还将用于唯一标识响应中的聚合。每个聚合都有一个特定的类型(上面代码段中的<aggregation_type>),通常是命名聚合体中的第一个键。每种类型的聚合都定义了自己的主体,这取决于聚合的性质(例如,特定字段上的平均聚合将定义计算平均值的字段)。在聚合类型定义的同一级别上,可以选择定义一组附加聚合,尽管这仅在定义的聚合具有bucketing性质时才有意义。在这种情况下,将为bucketing聚合生成的所有bucket计算在bucketing聚合级别上定义的子聚合。例如,如果在范围(range)聚合下定义了一组聚合,则将为定义的范围桶计算子聚合。

价值来源

一些聚合处理从聚合文档中提取的值。通常,这些值将从使用聚合的field key设置的特定文档字段中提取。还可以定义一个脚本来生成值(每个文档)。

为聚合配置filed和script设置时,script 将被视为 value 脚本。普通脚本是在文档级别上评估的(即脚本可以访问与文档相关的所有数据),而值脚本是在值级别上评估的。在这种模式下,将从配置字段中提取值,并使用脚本对这些值应用“转换”。

使用脚本时,还可以定义lang和params设置。前者定义了所使用的脚本语言(假设Elasticsearch中提供了适当的语言,默认情况下或作为插件)。后者允许将脚本中的所有“动态”表达式定义为参数,从而使脚本在调用之间保持静态(这将确保在Elasticsearch中使用缓存的编译脚本)。

Elasticsearch使用映射中字段的类型来确定如何运行聚合和格式化响应。然而,有两种情况下,Elasticsearch无法找出这些信息:未映射字段(例如,在跨多个索引的搜索请求的情况下,只有一些索引具有字段映射)和纯脚本。对于这些情况,可以使用value_type选项为Elasticsearch提供提示,该选项接受以下值:string、long(适用于所有整数类型)、double(适用于所有十进制类型,如float或scaled_float)、date、ip和boolean。