最近在使用 date_histogram
參數對日期范圍聚合時,發現聚合結果不正確,分析后發現和 ES 日期格式有關,記錄如下。
date_histogram
是 ES 提供針對日期屬性,進行區間聚合的一種方式,比如可以對如 1 分鍾,1 小時,等時間區間的文檔進行聚合。
舉例來說,我這里是對幾天內的文檔數據,按照 1 小時的時間區間進行聚合,payload 如下:
{
"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 小時的間隔進行返回,但實際上返回的結果卻是:
"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 總數也和期待的總數不一致,
后來查詢 ES Date 文檔后發現,ES 針對日期類型,默認的格式為:strict_date_optional_time||epoch_millis
, 也就是毫秒級別。
而之前建立 index 模板時,並未對日期屬性指定 format,所以默認選擇為上述毫秒格式的時間戳。但是入庫的數據,時間戳為秒。
自然,在聚合時,ES 會用毫秒的格式去聚合秒的數據,導致結果都是以 1970
開始。
修改也很簡單,在創建 index 模板時,顯示指定為秒格式即可:
"collect_time": {
"type": "date",
"format": "epoch_second"
},