为了在ES上根据时间进行统计,我在ES5.6.4上做了date_histogram聚合,查询语句如下所示
{ "aggregations": { "dateVspAggs": { "date_histogram": { "field": "timestamp", "interval": "day", "time_zone": "+08:00", "order": { "_key": "asc" }, "keyed": false, "min_doc_count": 0, "extended_bounds": { "min": 1551369600000, "max": 1554047999999 } } } } }因为是interval是day,所以我配置了time_zone 参数,从而避免查询结果的bucket统计范围有时差。 然而这个查询语句返回报错如下:
{ "error": { "root_cause": [ { "type": "illegal_argument_exception", "reason": "Field [timestamp_] of type [long] does not support custom time zones" } ], "type": "search_phase_execution_exception", "reason": "all shards failed", "phase": "query", "grouped": true, "failed_shards": [ { "shard": 0, "index": "test", "node": "ytXqsnmdSqmbKwEyw22fXg", "reason": { "type": "illegal_argument_exception", "reason": "Field [timestamp_] of type [long] does not support custom time zones" } } ] }, "status": 400 }报错信息显示time_zones的配置不支持long类型的字段。 不过值得一提的是相同的查询在ES2.x环境是能够成功执行的。
为此我特意查看了ES5.x的源码,发现ES5.x对number类型的字段校验过程中,如果发现它配置了time_zone 就会报异常,从ES5.x开始time_zone 只支持date类型。 相关代码如下所示 LegacyNumberFieldMapper::NumberFieldType::docValueFormat
public DocValueFormat docValueFormat(@Nullable String format, DateTimeZone timeZone) { if (timeZone != null) { throw new IllegalArgumentException("Field [" + name() + "] of type [" + typeName() + "] does not support custom time zones"); } if (format == null) { return DocValueFormat.RAW; } else { return new DocValueFormat.Decimal(format); } }为了进一步求证,我去github上提了问题,得到如下回答 https://github.com/elastic/elasticsearch/issues/42270#issuecomment-494445970
从ES的项目成员的回答中可以得出结论,time_zone的特性本来就是为date类型提供的,至于ES2.x中支持long类型只是因为这个版本对错误的配置更加容忍罢了,在ES5.x之后time_zone只支持date类型了。所以在ES中时间字段最好还是用date类型来存储。