Elasticsearch 汇总分组与配置
了解如何配置带有汇总查询和聚合分组的 Elasticsearch 汇总作业,以及时间序列数据分组的最佳实践。
为了保持灵活性,汇总作业(Rollup Jobs)的定义取决于未来查询可能如何使用这些数据。传统上,系统会强迫管理员决定要汇总哪些指标以及以什么间隔进行汇总。例如,按小时计算 cpu_time 的平均值。这是有限制的;如果将来管理员希望查看按小时计算且按 host_name 分区的 cpu_time 平均值,他们将无法实现。
当然,管理员可以决定按小时汇总 [hour, host] 元组,但随着分组键数量的增加,管理员需要配置的元组数量也会增加。此外,这些 [hours, host] 元组仅对小时级汇总有用……日、周或月汇总都需要新的配置。
Elasticsearch 的汇总作业不是强迫管理员提前决定应该汇总哪些单独的元组,而是基于未来查询可能用到的分组进行配置。例如,此配置
"groups" : {
"date_histogram": {
"field": "timestamp",
"fixed_interval": "1h",
"delay": "7d"
},
"terms": {
"fields": ["hostname", "datacenter"]
},
"histogram": {
"fields": ["load", "net_in", "net_out"],
"interval": 5
}
}
允许在 "timestamp" 字段上使用 date_histogram,在 "hostname" 和 "datacenter" 字段上使用 terms 聚合,以及在 "load"、"net_in" 或 "net_out" 字段中的任何一个上使用 histograms。
重要的是,这些聚合/字段可以以任何组合使用。此聚合
"aggs" : {
"hourly": {
"date_histogram": {
"field": "timestamp",
"fixed_interval": "1h"
},
"aggs": {
"host_names": {
"terms": {
"field": "hostname"
}
}
}
}
}
与此聚合同样有效
"aggs" : {
"hourly": {
"date_histogram": {
"field": "timestamp",
"fixed_interval": "1h"
},
"aggs": {
"data_center": {
"terms": {
"field": "datacenter"
}
},
"aggs": {
"host_names": {
"terms": {
"field": "hostname"
}
},
"aggs": {
"load_values": {
"histogram": {
"field": "load",
"interval": 5
}
}
}
}
}
}
}
你会注意到,第二个聚合不仅规模大得多,而且还交换了 "hostname" 上 terms 聚合的位置,这说明了聚合的顺序对汇总并不重要。同样,虽然 date_histogram 是汇总数据所必需的,但在查询时并非必需(尽管经常使用)。例如,这是汇总搜索(Rollup Search)可以执行的一个有效聚合
"aggs" : {
"host_names": {
"terms": {
"field": "hostname"
}
}
}
最终,在为作业配置 groups 时,请考虑将来在查询中可能如何对数据进行分区……然后将这些分区包含在配置中。因为汇总搜索允许分组字段的任何顺序或组合,你只需要决定一个字段是否对以后的聚合有用,以及你希望如何使用它(terms、histogram 等)。
每个汇总作业都必须有一个定义了间隔的日期直方图分组。Elasticsearch 同时理解 日历时间间隔和固定时间间隔。固定时间间隔相当容易理解;60s 意味着 60 秒。但 1M 是什么意思?一个月的时间取决于我们谈论的是哪个月,有些月份比其他月份长或短。这是日历时间的一个例子,该单位的持续时间取决于上下文。日历单位还受闰秒、闰年等因素的影响。
这一点很重要,因为汇总生成的存储桶(buckets)要么是日历间隔,要么是固定间隔,这限制了你以后如何查询它们。请参阅 请求必须是配置的倍数。
我们建议坚持使用固定时间间隔,因为它们更容易理解,并且在查询时更灵活。它会在闰事件期间在数据中引入一些偏差,你将不得不以固定数量(30天)而不是实际的日历长度来考虑月份。然而,这通常比在查询时处理日历单位更容易。
单位的倍数始终是“固定”的。例如,2h 始终是固定的 7200 秒。单个单位可以是固定或日历的,具体取决于单位
| 单位 | 日历 | 固定 |
|---|---|---|
| millisecond | 不适用 | 1ms, 10ms, 等等 |
| second | 不适用 | 1s, 10s, 等等 |
| minute | 1m |
2m, 10m, 等等 |
| hour | 1h |
2h, 10h, 等等 |
| day | 1d |
2d, 10d, 等等 |
| week | 1w |
不适用 |
| month | 1M |
不适用 |
| quarter | 1q |
不适用 |
| year | 1y |
不适用 |
对于某些既有固定又有日历的单位,你可能需要用更小的单位来表示数量。例如,如果你想要一个固定的一天(而不是日历天),你应该指定 24h 而不是 1d。同样,如果你想要固定的几小时,请指定 60m 而不是 1h。这是因为单个数量意味着日历时间,并且限制你将来只能按日历时间进行查询。
以前,Rollup 处理具有异构映射(多个、不相关/不重叠的映射)的索引的方式存在限制。当时的建议是为每个数据“类型”配置一个单独的作业。例如,你可能会为你启用的每个 Beats 模块配置一个单独的作业(一个用于 process,另一个用于 filesystem,等等)。
这一建议是受内部实现细节的驱动,如果使用单个“合并”作业,这些细节可能会导致文档计数不准确。
这一限制现已消除。从 6.4.0 版本开始,将所有汇总配置合并到一个作业中被视为最佳实践。
例如,如果你的索引有两种类型的文档
{
"timestamp": 1516729294000,
"temperature": 200,
"voltage": 5.2,
"node": "a"
}
and
{
"timestamp": 1516729294000,
"price": 123,
"title": "Foo"
}
最佳实践是将它们合并到一个涵盖这两种文档类型的单个汇总作业中,如下所示
PUT _rollup/job/combined
{
"index_pattern": "data-*",
"rollup_index": "data_rollup",
"cron": "*/30 * * * * ?",
"page_size": 1000,
"groups": {
"date_histogram": {
"field": "timestamp",
"fixed_interval": "1h",
"delay": "7d"
},
"terms": {
"fields": [ "node", "title" ]
}
},
"metrics": [
{
"field": "temperature",
"metrics": [ "min", "max", "sum" ]
},
{
"field": "price",
"metrics": [ "avg" ]
}
]
}
以前,“重叠”作业配置上的文档计数存在一个问题,这是由相同的内部实现细节引起的。如果有两个保存到同一索引的 Rollup 作业,其中一个作业是另一个作业的“子集”,那么对于某些聚合安排,文档计数可能会不正确。
此问题也已在 6.4.0 版本中消除。