Elasticsearch 参考指南(日期直方图聚合)
日期直方图聚合
类似于直方图的多桶聚合,但它只能应用于日期值,由于在Elasticsearch内部将日期表示为long
值,因此也可以在日期上使用普通的histogram
,但准确性会受到影响,原因是基于时间的间隔不是固定的(想想闰年和一个月的天数),因此,我们需要对基于时间的数据提供特殊支持。从功能的角度来看,这个直方图支持与普通直方图相同的特性,主要的区别是间隔可以由日期/时间表达式指定。
请求桶间隔一个月。
POST /sales/_search?size=0 { "aggs" : { "sales_over_time" : { "date_histogram" : { "field" : "date", "interval" : "month" } } } }
时间间隔可用的表达式:year
(1y
)、quarter
(1q
)、month
(1M
)、week
(1w
)、day
(1d
)、hour
(1h
)、minute
(1M
)、second
(1s
)。
时间值也可以通过时间单位解析所支持的缩写来指定,注意,不支持小数时间值,但是你可以通过转移到另一个时间单位来解决这个问题(例如,1.5h
可以被指定为90m
),还要注意,大于天的时间间隔不支持任意值,但只能是一个单位大(例如,1y
是有效的,2y
不是)。
POST /sales/_search?size=0 { "aggs" : { "sales_over_time" : { "date_histogram" : { "field" : "date", "interval" : "90m" } } } }
键
在内部,日期被表示为64位数字,表示从纪元开始算起的时间戳,这些时间戳作为桶的key
返回,key_as_string
是与使用format
参数指定的格式转换成格式化日期字符串相同的时间戳:
format
,那么它将使用字段映射中指定的第一个日期格式。POST /sales/_search?size=0 { "aggs" : { "sales_over_time" : { "date_histogram" : { "field" : "date", "interval" : "1M", "format" : "yyyy-MM-dd" } } } }
"format" : "yyyy-MM-dd"
=> 支持表达日期格式模式
响应:
{ ... "aggregations": { "sales_over_time": { "buckets": [ { "key_as_string": "2015-01-01", "key": 1420070400000, "doc_count": 3 }, { "key_as_string": "2015-02-01", "key": 1422748800000, "doc_count": 2 }, { "key_as_string": "2015-03-01", "key": 1425168000000, "doc_count": 2 } ] } } }
时区
在Elasticsearch中日期时间被存储在UTC,默认情况下,所有桶和四舍五入都是在UTC中完成的,可以使用time_zone
参数指示桶使用不同的时区。
时区可以指定为ISO 8601 UTC偏移量(例如+01:00
或-08:00
),也可以指定为时区id,这是TZ数据库(如America/Los_Angeles
)中使用的标识符。
考虑下面的示例:
PUT my_index/_doc/1?refresh { "date": "2015-10-01T00:30:00Z" } PUT my_index/_doc/2?refresh { "date": "2015-10-01T01:30:00Z" } GET my_index/_search?size=0 { "aggs": { "by_day": { "date_histogram": { "field": "date", "interval": "day" } } } }
如果没有指定时区,则使用UTC,这将导致将这两个文档放入同一天的桶中,该桶从2015年10月1日午夜UTC开始:
{ ... "aggregations": { "by_day": { "buckets": [ { "key_as_string": "2015-10-01T00:00:00.000Z", "key": 1443657600000, "doc_count": 2 } ] } } }
如果指定了-01:00
的time_zone
,那么午夜从UTC午夜前一小时开始:
GET my_index/_search?size=0 { "aggs": { "by_day": { "date_histogram": { "field": "date", "interval": "day", "time_zone": "-01:00" } } } }
现在第一个文档落入2015年9月30日的桶,第二个文档落入2015年10月1日的桶:
{ ... "aggregations": { "by_day": { "buckets": [ { "key_as_string": "2015-09-30T00:00:00.000-01:00", "key": 1443574800000, "doc_count": 1 }, { "key_as_string": "2015-10-01T00:00:00.000-01:00", "key": 1443661200000, "doc_count": 1 } ] } } }
key_as_string
值表示在指定时区中每天的午夜。
interval
预期的大小略有不同。例如,考虑在CET
时区启动DST:2016年3月27日凌晨2点,时钟拨快1小时至当地时间凌晨3点,当使用day
作为interval
时,覆盖当天的桶将只保存23个小时的数据,而其他桶通常是24小时。对于较短的间隔,如12h,也是如此,在这里,当DST转变发生时,我们在3月27日早上只有一个11小时的桶。偏移量
offset
参数用于通过指定的正(+
)或负偏移(-
)的持续时间来更改每个桶的起始值,例如1h
为1小时或1d
为一天,有关更多可能的持续时间选项,请参阅时间单位。
例如,当使用day
的间隔时,每个桶从午夜运行到午夜,将offset
参数设置为+6h
将更改每个桶从早上6点运行到早上6点:
PUT my_index/_doc/1?refresh { "date": "2015-10-01T05:30:00Z" } PUT my_index/_doc/2?refresh { "date": "2015-10-01T06:30:00Z" } GET my_index/_search?size=0 { "aggs": { "by_day": { "date_histogram": { "field": "date", "interval": "day", "offset": "+6h" } } } }
上面的请求将文档分组为从早上6点开始的桶,而不是从午夜开始的单个桶:
{ ... "aggregations": { "by_day": { "buckets": [ { "key_as_string": "2015-09-30T06:00:00.000Z", "key": 1443592800000, "doc_count": 1 }, { "key_as_string": "2015-10-01T06:00:00.000Z", "key": 1443679200000, "doc_count": 1 } ] } } }在进行
time_zone
调整之后,计算每个桶的起始offset
。keyed响应
将keyed
标志设置为true
将把唯一的字符串键与每个桶关联起来,并以hash而不是数组的形式返回范围:
POST /sales/_search?size=0 { "aggs" : { "sales_over_time" : { "date_histogram" : { "field" : "date", "interval" : "1M", "format" : "yyyy-MM-dd", "keyed": true } } } }
响应:
{ ... "aggregations": { "sales_over_time": { "buckets": { "2015-01-01": { "key_as_string": "2015-01-01", "key": 1420070400000, "doc_count": 3 }, "2015-02-01": { "key_as_string": "2015-02-01", "key": 1422748800000, "doc_count": 2 }, "2015-03-01": { "key_as_string": "2015-03-01", "key": 1425168000000, "doc_count": 2 } } } } }
脚本
与普通直方图一样,支持文档级别脚本和值级别脚本,还可以使用order
设置控制返回的桶的顺序,并基于min_doc_count
设置过滤返回的桶(默认情况下,将返回匹配文档的第一个桶和最后一个桶之间的所有桶)。这个直方图还支持extended_bounds
设置,它允许扩展直方图的界限超过数据本身(关于为什么要这样做的更多信息,请参阅此处的解释)。
缺失值
missing
参数定义了如何处理缺失值的文档,默认情况下,它们将被忽略,但也可以将它们视为有值来处理。
POST /sales/_search?size=0 { "aggs" : { "sale_date" : { "date_histogram" : { "field" : "date", "interval": "year", "missing": "2000/01/01" } } } }
publish_date
字段中没有值的文档将落入具有值为2000-01-01
的文档的同一个桶。
顺序
默认情况下,返回的桶按key
升序排序,不过可以使用order
设置控制顺序行为,支持与Terms聚合相同的order
功能。
在6.0.0中已弃用
使用_key
而不是_time
来根据它们的日期/键来排序桶。
使用脚本通过星期几聚合
在某些情况下,日期直方图不能帮助我们,例如,当我们需要通过星期几聚合结果时,在这种情况下,为了克服这个问题,我们可以使用一个返回星期几的脚本:
POST /sales/_search?size=0 { "aggs": { "dayOfWeek": { "terms": { "script": { "lang": "painless", "source": "doc['date'].value.dayOfWeek" } } } } }
响应:
{ ... "aggregations": { "dayOfWeek": { "doc_count_error_upper_bound": 0, "sum_other_doc_count": 0, "buckets": [ { "key": "7", "doc_count": 4 }, { "key": "4", "doc_count": 3 } ] } } }
响应将包含以星期为键的所有桶:1为星期一,2为星期二...7为星期日。