最近在使用 date_histogram
参数对日期范围聚合时,发现聚合结果不正确,分析后发现和 ES 日期格式有关,记录以下。html
date_histogram
是 ES 提供针对日期属性,进行区间聚合的一种方式,好比能够对如 1 分钟,1 小时,等时间区间的文档进行聚合。sql
举例来讲,我这里是对几天内的文档数据,按照 1 小时的时间区间进行聚合,payload 以下:app
{ "size": 100, "query": { "range": { "collect_time": { "gte": 1610265800, # 开始时间 "lt": "now" # 结束时间 } } }, "aggs": { "group_by_hour": { "date_histogram": { "field": "collect_time", # collect_time 为日期属性,按照该属性进行聚合 "interval": "hour", # 聚合的区间为小时 "format": "yyyy-MM-dd-hh" # 返回结果中的日期显示格式 }, "aggs": { "avgrtt": { "avg": { "field": "avgrtt" # 聚合待求平均值的字段 } } } } } }
按照期待的理解,返回的数据应该按照 1 小时的间隔进行返回,但实际上返回的结果倒是:elasticsearch
"aggregations": { "group_by_hour": { "buckets": [ { "key_as_string": "1970-01-19-03", "key": 1609200000, "doc_count": 70, "avgrtt": { "value": 1.0 } } ] } }
传入的最小日期为 1610265800 ,也就是 2021-01-10 16:03:20. 但这里聚合后的时间结果是 1970-01-19-03。说明聚合的粒度根本不对,并且这里聚合 doc 总数也和期待的总数不一致,ide
后来查询 ES Date 文档后发现,ES 针对日期类型,默认的格式为:strict_date_optional_time||epoch_millis
, 也就是毫秒级别。ui
而以前创建 index 模板时,并未对日期属性指定 format,因此默认选择为上述毫秒格式的时间戳。可是入库的数据,时间戳为秒。code
天然,在聚合时,ES 会用毫秒的格式去聚合秒的数据,致使结果都是以 1970
开始。orm
修改也很简单,在建立 index 模板时,显示指定为秒格式便可:htm
"collect_time": { "type": "date", "format": "epoch_second" },