5.2.4. 复合聚合

复合聚合

多桶聚合是指从不同的源创建的复合桶.

与其他 多桶 聚合不同的是,复合 聚合可用于高效地对多层聚合中的 所有 桶进行分页。 这种聚合提供了一种流特定聚合的所有桶的方法,类似于 scroll 对文档做的操作。

复合桶是根据每个文档提取/创建的值的组合构建的,每个组合都被视为一个复合桶。

例如下面的文档:

{
    "keyword": ["foo", "bar"],
    "number": [23, 65, 76]
}

… 创建下面的复合桶, 使用 keyword 和 number 两个字段的值进行聚合:

{ "keyword": "foo", "number": 23 }
{ "keyword": "foo", "number": 65 }
{ "keyword": "foo", "number": 76 }
{ "keyword": "bar", "number": 23 }
{ "keyword": "bar", "number": 65 }
{ "keyword": "bar", "number": 76 }

Values source

sources 参数控制用于构建复合桶的源。 定义 sources 的顺序很重要,因为它还控制着键的返回顺序。

每个sources的名称必须是唯一的.

下面是三种不同类型的 values source:

Terms

terms 的 value source 相当于一个简单的 terms 聚合。 这些值是从 field 或 script 中提取的,与 terms 聚合完全一样。

使用 field 为复合桶创建值:

GET /_search
{
    "aggs" : {
        "my_buckets": {
            "composite" : {
                "sources" : [
                    { "product": { "terms" : { "field": "product" } } }
                ]
            }
        }
     }
}

也可以使用 script 为复合桶创建值:

GET /_search
{
    "aggs" : {
        "my_buckets": {
            "composite" : {
                "sources" : [
                    {
                        "product": {
                            "terms" : {
                                "script" : {
                                    "source": "doc['product'].value",
                                    "lang": "painless"
                                }
                            }
                        }
                    }
                ]
            }
        }
    }
}

Histogram

histogram 值源可应用于数值,以在值上构建固定大小的间隔。 interval 参数定义如何转换数值。 例如,将 interval 的值设为5,会将任何数值转换到最接近的间隔, 值 101 将会被转换为 100 ,这是这个键的间隔在100到105之间。

Example:

GET /_search
{
    "aggs" : {
        "my_buckets": {
            "composite" : {
                "sources" : [
                    { "histo": { "histogram" : { "field": "price", "interval": 5 } } }
                ]
            }
        }
    }
}

这些值是从数字字段或返回数字值的脚本中构建的:

GET /_search
{
    "aggs" : {
        "my_buckets": {
            "composite" : {
                "sources" : [
                    {
                        "histo": {
                            "histogram" : {
                                "interval": 5,
                                "script" : {
                                    "source": "doc['price'].value",
                                    "lang": "painless"
                                }
                            }
                        }
                    }
                ]
            }
        }
    }
}

Date Histogram

date_histogramhistogram值源相似,但不同之处是由日期/时间表达式指定的时间间隔::

GET /_search
{
    "aggs" : {
        "my_buckets": {
            "composite" : {
                "sources" : [
                    { "date": { "date_histogram" : { "field": "timestamp", "calendar_interval": "1d" } } }
                ]
            }
        }
    }
}

上面的示例每天创建一个间隔,并将所有timestamp值转换为其最接近的间隔的开始值。间隔的可用表达式:季度hour分钟

时间值也可以通过时间单位支持的缩写来指定。 请注意,不支持小数时间值,但是您可以通过转移到其他时间单位来解决此问题(例如,可以将1.5h指定为90分钟)。

Format

在内部,日期表示为一个64位的数字,表示自该时间点以来的毫秒数。这些时间戳作为存储桶键返回。可以使用格式化参数指定的格式来返回格式化的日期字符串:

GET /_search
{
    "aggs" : {
        "my_buckets": {
            "composite" : {
                "sources" : [
                    {
                        "date": {
                            "date_histogram" : {
                                "field": "timestamp",
                                "calendar_interval": "1d",
                                "format": "yyyy-MM-dd" 
                            }
                        }
                    }
                ]
            }
        }
    }
}
  1. 支持表示日期格式模式

时区

Elasticsearch使用世界标准时间(UTC)存储日期时间。 默认情况下,所有存储和取整也是使用世界标准时间(UTC)。 time_zone 参数用于指定存储时所使用不同的时区

时区可以指定为 ISO 8601 UTC 偏移 (例如 +01:00 或者 -08:00) ,也可以指定为时区数据库(TimeZoneDB)中的时区编号,例如 America/Los_Angeles.

混合不同的值源

sources 参数数接受源数组的值。可以混合使用不同的值源来创建复合存储桶。例如:

GET /_search
{
    "aggs" : {
        "my_buckets": {
            "composite" : {
                "sources" : [
                    { "date": { "date_histogram": { "field": "timestamp", "calendar_interval": "1d" } } },
                    { "product": { "terms": {"field": "product" } } }
                ]
            }
        }
    }
}

这将从两个值源创建的值中( date_histogramterms)创建复合桶。
每个桶均由两个值组成, 其中每一个值源都在聚合中定义。 允许任何类型的组合,并且在存储桶中,数组中的排序将被保留。

GET /_search
{
    "aggs" : {
        "my_buckets": {
            "composite" : {
                "sources" : [
                    { "shop": { "terms": {"field": "shop" } } },
                    { "product": { "terms": { "field": "product" } } },
                    { "date": { "date_histogram": { "field": "timestamp", "calendar_interval": "1d" } } }
                ]
            }
        }
    }
}

排序

默认情况下,复合桶按其自然顺序排序。 值按其值的升序排序。 当请求多个值源时,将对每个值源进行排序, 将复合桶的第一个值与另一个复合桶的第一个值进行比较 ,如果它们相等,将比较复合桶中的下一个值。 这就意味着复合桶 [foo, 100] 被认为小于 [foobar, 0] ,因为 foo 被认为小于 foobar。 可以通过直接将 order 设置为 asc (默认的) 或者 desc (降序) 来定义每个值源的排序方式。例如:

GET /_search
{
    "aggs" : {
        "my_buckets": {
            "composite" : {
                "sources" : [
                    { "date": { "date_histogram": { "field": "timestamp", "calendar_interval": "1d", "order": "desc" } } },
                    { "product": { "terms": {"field": "product", "order": "asc" } } }
                ]
            }
        }
    }
}

… 当比较源为 date_histogram 的值时,将按降序对复合桶进行排序;当比较源 terms 的值时,将按升序对复合桶进行排序。

缺失桶

默认情况下,没有给定源值的文档将被忽略。 可以通过将 missing_bucket 设置为 true (默认值是 false),把它们包括在响应中。例如 :

GET /_search
{
    "aggs" : {
        "my_buckets": {
            "composite" : {
                "sources" : [
                    { "product_name": { "terms" : { "field": "product", "missing_bucket": true } } }
                ]
            }
        }
     }
}

在上面的示例中,当product 字段没有值时,源 product_name 将会被设置一个显式的 null 值 。 通过源 order 参数指定 null 值应该排在首位(升序, asc) 或者是末尾 (降序, desc).

设置返回数量

通过设置 size 参数指定返回复合桶的数量。 每个复合桶都被视为单个桶, 当我们将size指定为10时,将返回从源值创建的前10个复合桶。 响应包含数组中每个复合桶的值,该数组包含从每个值源提取的值。

分页

如果复合桶的数量过多(或者不知其数量) ,从而无法在单个响应中返回,那么可以将检索拆分为多个请求。 由于复合存储桶在本质上是扁平的, 所以请求的 size 恰好是将在响应中返回的复合存储桶的数量 (假设它们能够返回 size 的复合桶). 如果要检索所有复合存储桶,最好使用较小的size (100 或者 1000) ,然后使用 after 参数去检索余下的结果。 例如:

GET /_search
{
    "aggs" : {
        "my_buckets": {
            "composite" : {
                "size": 2,
                "sources" : [
                    { "date": { "date_histogram": { "field": "timestamp", "calendar_interval": "1d" } } },
                    { "product": { "terms": {"field": "product" } } }
                ]
            }
        }
    }
}

… 返回的结果:

{
    ...
    "aggregations": {
        "my_buckets": {
            "after_key": {"date": 1494288000000,
                "product": "mad max"
            },
            "buckets": [
                {
                    "key": {
                        "date": 1494201600000,
                        "product": "rocky"
                    },
                    "doc_count": 1
                },
                {
                    "key": {
                        "date": 1494288000000,
                        "product": "mad max"
                    },
                    "doc_count": 2
                }
            ]
        }
    }
}

①. 查询最后一个复合桶。

注意
after_key 等于Pipeline aggregations.执行任何过滤前返回的最后一个桶 。如果通过pipeline aggregation(管道聚合)过滤/删除全部的桶, 那么 after_key将包含过滤前的最后一个桶.

after 参数可以被用于检索在前一个检索中返回的最后一个复合桶。 下面的示例中, 可以在 after_key 值中找到前一个检索中返回的最后一个桶,并且根据该值,使用下面的方法进行分页检索:

GET /_search
{
    "aggs" : {
        "my_buckets": {
            "composite" : {
                "size": 2,
                 "sources" : [
                    { "date": { "date_histogram": { "field": "timestamp", "calendar_interval": "1d", "order": "desc" } } },
                    { "product": { "terms": {"field": "product", "order": "asc" } } }
                ],
                "after": { "date": 1494288000000, "product": "mad max" }}
        }
    }
}

① 聚合中的排序字段应该使用 after 的字段.

子聚合

multi-bucket (多桶)聚合一样, composite (复合)聚合也可以包含子聚合. 这些子聚合可用于计算其他存储桶或有关此父聚合创建的每个复合桶的统计信息。 如,以下示例计算每个复合桶字段的平均值:

GET /_search
{
    "aggs" : {
        "my_buckets": {
            "composite" : {
                 "sources" : [
                    { "date": { "date_histogram": { "field": "timestamp", "calendar_interval": "1d", "order": "desc" } } },
                    { "product": { "terms": {"field": "product" } } }
                ]
            },
            "aggregations": {
                "the_avg": {
                    "avg": { "field": "price" }
                }
            }
        }
    }
}

… returns:

{
    ...
    "aggregations": {
        "my_buckets": {
            "after_key": {
                "date": 1494201600000,
                "product": "rocky"
            },
            "buckets": [
                {
                    "key": {
                        "date": 1494460800000,
                        "product": "apocalypse now"
                    },
                    "doc_count": 1,
                    "the_avg": {
                        "value": 10.0
                    }
                },
                {
                    "key": {
                        "date": 1494374400000,
                        "product": "mad max"
                    },
                    "doc_count": 1,
                    "the_avg": {
                        "value": 27.0
                    }
                },
                {
                    "key": {
                        "date": 1494288000000,
                        "product" : "mad max"
                    },
                    "doc_count": 2,
                    "the_avg": {
                        "value": 22.5
                    }
                },
                {
                    "key": {
                        "date": 1494201600000,
                        "product": "rocky"
                    },
                    "doc_count": 1,
                    "the_avg": {
                        "value": 10.0
                    }
                }
            ]
        }
    }
}

Pipeline aggregations(管道聚合)

当前复合聚合与管道聚合并不兼容,在大多数情况下也没有意义。 例如, 由于复合聚合的分页特性,单个逻辑分区(例如一天)可能分布在多个页面上。 由于管道聚合纯粹是对桶的最终列表的后处理,因此在复合页面上运行类似派生的操作可能会导致不准确的结果,因为它只考虑了该页面上的“部分”结果。

将来可能会支持自我包含在单个桶中的管道聚合 (例如 bucket_selector)

本文章首发在 LearnKu.com 网站上。

本译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。
上一篇 下一篇
CrazyZard
贡献者:5
讨论数量: 0
发起讨论 只看当前版本


暂无话题~