Elasticsearch Date Histogram 时区问题

前言:项目中使用 Elasticsearch (以下简称 ES)获取数据,在用 Date Histogram 做聚合查询涉及到时区问题.特此记录一下.

ES中对时间类型字段,是统一采用 UTC 时间记录,详见此链接关于UTC和GMT时间辨析

整个地球分为二十四时区,每个时区都有自己的本地时间。在国际无线电通信场合,为了统一起见,使用一个统一的时间,称为通用协调时(UTC,Universal Time Coordinated)。
UTC与GMT(格林尼治平均时, Greenwich MeanTime)一样,都与英国伦敦的本地时相同。
本地时间转化为UTC,公式: UTC + 时区差 = 本地时间


本例中用的是 ES 版本为 2.4.4,
开发中采用 ES JavaAPI 方式操作.点此查看官方2.4 Java API


本测试案例中有一个索引下 字段为 @timestamp 存储的值的格式为 2017-05-24T12:56:28.000+08:00 .说明该条记录时间是 2017年5月24号12点56分(28秒),这个地方的本地时领先UTC八个小时.
对我们而言就是本地这个时间点.

本例采用以下代码进行聚合测试

// 聚合查询配置
AggregationBuilder dateAggs =
                AggregationBuilders
                        .dateHistogram("dateAggs") // 别名
                        .field("@timestamp")  // 指定聚合哪个时间字段
                        .interval(DateHistogramInterval.DAY) // 按天聚合
                        .minDocCount(0L) // 默认为0
                        .order(Histogram.Order.KEY_ASC) // 按时间正序
                        .timeZone("+08:00") // 指定时区
                        .subAggregation( // 子聚合
                                AggregationBuilders
                                        .sum("sumAggs")
                                        .field("tx_count")
                        );

查询 2017-05-16 00:00:00 到 2017-05-21 00:00:00 每天的交易总数

  1. 如果不加 .timeZone("+08:00") // 指定时区,结果为

    dateKeycount
    2017-05-15T00:00:00.000ZXXX
    2017-05-16T00:00:00.000ZXXX
    2017-05-17T00:00:00.000ZXXX
    2017-05-18T00:00:00.000ZXXX
    2017-05-19T00:00:00.000ZXXX
    2017-05-20T00:00:00.000ZXXX

    这个结果集明显就是有误的,这个会与之后的对比

  2. .timeZone("+08:00") // 指定时区,结果为

    dateKeycount
    2017-05-15T16:00:00.000ZSSS
    2017-05-16T16:00:00.000ZSSS
    2017-05-17T16:00:00.000ZSSS
    2017-05-18T16:00:00.000ZSSS
    2017-05-19T16:00:00.000ZSSS

    注意: 此时看到结果集的时间字段有 16时,说明 ES 按时间聚合之后 返回的时间值是按UTC计算 ,也就是比本地时间少 8 个小时,最后在遍历聚合结果的时候再对时间字段加上8个小时即可.最后会附上处理 UTC 格式的方法.

ES 中提供了对返回的时间进行时区处理,步骤如下:

SearchResponse response = ...;
DateHistogram timeHistogram = response.getAggregations().get("dateAggs");
// For each entry
for (DateHistogram.Bucket timeHistogramEntry : timeHistogram.getBuckets()) {
    DateTime keyAsDate = timeHistogramEntry.getKeyAsDate();
    // 将返回的时间转化为本地时间
    Date dateKey = keyAsDate.toDateTime(DateTimeZone.forTimeZone(TimeZone.getTimeZone("GMT+8")).toDate();
    String dateKey = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(dateKey);
}

总结:
ES 做时间聚合查询的时候,是按 UTC 去查,并且最后返回的结果也为 UTC,所以我们在用Java API查询的时候指定 timeZone 会是比较好的解决方式.最后对时间结果格式化即可.
而Kibana上查询并不存在此问题,当然,肯定也是作了处理的.

另附,格式UTC时间方法:

时间格式: yyyy-MM-dd'T'HH:mm:ss.SSSXXX
Date date = new Date();
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX");
String str = dateFormat.format(date);
System.out.println(str); // 2017-05-16T10:10:36.602+08:00

String dateStr = "2017-05-15T16:00:00.000Z";
Date newDate = dateFormat.parse(dateStr);
System.out.println(newDate); // Tue May 16 00:00:00 GMT+08:00 2017

最后,希望通过这篇博文能给你带来帮助,感谢你的阅读.

Date Histogram是一个在Elasticsearch中使用的聚合方法,用于按照时间间隔对日期进行分组和计数。它类似于Histogram,但是支持日期表达式作为区间。 Date Histogram的用法相对于Histogram来说更加灵活,可以根据指定的日期表达式来对时间进行分组。例如,你可以将间隔(interval)指定为一个月,它会智能地知道2月比12月要短,并且还能根据时区进行定制,以便根据用户的时区来生成图形,而不是根据服务器的时区。 通常的Histogram桶也可以处理日期,但是它不具备自动识别日期并根据日期的特性进行处理的能力。而Date Histogram可以根据指定的时间间隔自动识别日期,并且能够合理地处理时区,这样就可以根据客户端的时区来进行图表的定制。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [date_histogram](https://blog.csdn.net/opera95/article/details/78614244)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [[Elasticsearch] 聚合 - 时间数据处理(Looking at Time)](https://blog.csdn.net/dm_vincent/article/details/42594043)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值