问题
为了在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类型来存储。