Elasticsearch按1小时聚合@timestamp时如何保留分钟信息?
嘿,我明白你的需求:用1小时粒度的date_histogram聚合,但希望结果里的key能带上原始时间戳的分钟信息,而不是默认的整点00分,同时又不想改成1分钟聚合。这其实是因为date_histogram的默认分组逻辑导致的,下面给你讲清楚原因和可行的解决方案:
为什么当前结果只有整点分钟
当你把interval设为1h时,Elasticsearch会自动将每个聚合桶的起始时间对齐到整点(比如10:00、11:00),format参数只是把这个整点时间格式化成字符串,所以分钟自然是00——这不是format的问题,是聚合的分组规则决定的。
方案1:获取桶内某条文档的真实分钟(最贴合需求)
如果你想让每个1小时桶关联一个包含真实分钟的时间(比如桶内最早或最晚的文档时间),可以在date_histogram里嵌套一个top_hits聚合,专门抓取这个时间:
{ "aggs": { "hourly_stats": { "date_histogram": { "field": "@timestamp", "interval": "1h", "format": "yyyy-MM-dd H:m:s" }, "aggs": { "sample_time_with_minute": { "top_hits": { "size": 1, "sort": [{"@timestamp": "asc"}], // 取桶内最早的时间,改成"desc"就是最晚的 "_source": ["@timestamp"] } } } } } }
返回结果里,每个桶的sample_time_with_minute.hits.hits[0]._source.@timestamp就是带分钟的真实时间(比如你例子里的2020-12-09T13:50:46.056000Z),你可以用这个值作为“带分钟的key”来展示,同时聚合还是保持1小时粒度。
方案2:给桶设置固定分钟偏移
如果你只是想让所有桶的起始时间带上固定的分钟(比如你例子里的50分),可以用offset参数调整桶的起始点:
'stats': { 'date_histogram': { 'field': '@timestamp', 'interval': '1h', 'format': 'yyyy-MM-dd H:m:s', 'offset': '50m' // 让每个桶从XX:50开始,比如13:50-14:50 } }
这样每个桶的key_as_string就会显示成2020-12-09 13:50:00这种格式。不过要注意,这个偏移是固定的,不是从文档里动态提取的哦。
不推荐的方案:脚本自定义key
如果硬要让key本身包含分钟,又想按小时聚合,你可能会想到用terms聚合配合脚本提取小时+分钟,但这样会把同一小时内不同分钟的文档分成不同的桶,完全违背了你“不执行1分钟聚合”的需求,所以这个方案只适合特殊场景,不推荐你用。
内容的提问来源于stack exchange,提问作者Sharmiko

