Elasticsearch Date类型,时间存储相关说明。

JSON 2016-08-22 18:53:14 67184

从昨晚开始,到今天中午之前,一直在纠结时间存储问题,昨晚是纠结时间取出来的问题。

其实我的想法很简单,我就想java.util.Date  存储到 Elasticsearch  ,然后从 Elasticsearch  中再取出来的时候,它是个Date ,不需要我任何转换。

但是发现好像不行。

我开始在创建 Mapping  的时候,就是为:

//...省略部分代码
.startObject("create_date").field("type","date").field("format","yyyy-MM-dd HH:mm:ss").endObject()
//...省略部分代码

指定了Type Date ,并且format yyyy-MM-dd HH:mm:ss ,然后new Date(); 插入后报错:

message [MapperParsingException[failed to parse [create_date]]; nested: IllegalArgumentException[Invalid format: "2016-07-04T03:03:12.616Z" is malformed at "T03:03:12.616Z"];]

根据错误提示,我先把时间格式化,然后插入:

result.put("create_date", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(create_date));

然后插入OK。后来我看了源码,才恍然大悟。新版本(我不知道从什么版本开始,我以前最开始用的是0.9)值是根据value 的类型来判断。我贴一下。

org.elasticsearch.common.xcontent.XContentBuilder 1248 行。

private void writeValue(Object value) throws IOException {
	if (value == null) {
		generator.writeNull();
		return;
	}
	Class<?> type = value.getClass();
	if (type == String.class) {
		generator.writeString((String) value);
	} else if (type == Integer.class) {
		generator.writeNumber(((Integer) value).intValue());
	} else if (type == Long.class) {
		generator.writeNumber(((Long) value).longValue());
	} else if (type == Float.class) {
		generator.writeNumber(((Float) value).floatValue());
	} else if (type == Double.class) {
		generator.writeNumber(((Double) value).doubleValue());
	} else if (type == Byte.class) {
		generator.writeNumber(((Byte)value).byteValue());
	} else if (type == Short.class) {
		generator.writeNumber(((Short) value).shortValue());
	} else if (type == Boolean.class) {
		generator.writeBoolean(((Boolean) value).booleanValue());
	} else if (type == GeoPoint.class) {
		generator.writeStartObject();
		generator.writeNumberField("lat", ((GeoPoint) value).lat());
		generator.writeNumberField("lon", ((GeoPoint) value).lon());
		generator.writeEndObject();
	} else if (value instanceof Map) {
		writeMap((Map) value);
	} else if (value instanceof Path) {
		//Path implements Iterable<Path> and causes endless recursion and a StackOverFlow if treated as an Iterable here
		generator.writeString(value.toString());
	} else if (value instanceof Iterable) {
		generator.writeStartArray();
		for (Object v : (Iterable<?>) value) {
			writeValue(v);
		}
		generator.writeEndArray();
	} else if (value instanceof Object[]) {
		generator.writeStartArray();
		for (Object v : (Object[]) value) {
			writeValue(v);
		}
		generator.writeEndArray();
	} else if (type == byte[].class) {
		generator.writeBinary((byte[]) value);
	/*	注意这里:如果是Date类型,就是以字符串输出。
		如果你跟进去看。代码在下个片段。
	*/
	} else if (value instanceof Date) {
		generator.writeString(XContentBuilder.defaultDatePrinter.print(((Date) value).getTime()));
	} else if (value instanceof Calendar) {
		generator.writeString(XContentBuilder.defaultDatePrinter.print((((Calendar) value)).getTimeInMillis()));
	} else if (value instanceof ReadableInstant) {
		generator.writeString(XContentBuilder.defaultDatePrinter.print((((ReadableInstant) value)).getMillis()));
	} else if (value instanceof BytesReference) {
		BytesReference bytes = (BytesReference) value;
		if (!bytes.hasArray()) {
			bytes = bytes.toBytesArray();
		}
		generator.writeBinary(bytes.array(), bytes.arrayOffset(), bytes.length());
	} else if (value instanceof BytesRef) {
		BytesRef bytes = (BytesRef) value;
		generator.writeBinary(bytes.bytes, bytes.offset, bytes.length);
	} else if (value instanceof Text) {
		Text text = (Text) value;
		if (text.hasBytes() && text.bytes().hasArray()) {
			generator.writeUTF8String(text.bytes().array(), text.bytes().arrayOffset(), text.bytes().length());
		} else if (text.hasString()) {
			generator.writeString(text.string());
		} else {
			BytesArray bytesArray = text.bytes().toBytesArray();
			generator.writeUTF8String(bytesArray.array(), bytesArray.arrayOffset(), bytesArray.length());
		}
	} else if (value instanceof ToXContent) {
		((ToXContent) value).toXContent(this, ToXContent.EMPTY_PARAMS);
	} else if (value instanceof double[]) {
		generator.writeStartArray();
		for (double v : (double[]) value) {
			generator.writeNumber(v);
		}
		generator.writeEndArray();
	} else if (value instanceof long[]) {
		generator.writeStartArray();
		for (long v : (long[]) value) {
			generator.writeNumber(v);
		}
		generator.writeEndArray();
	} else if (value instanceof int[]) {
		generator.writeStartArray();
		for (int v : (int[]) value) {
			generator.writeNumber(v);
		}
		generator.writeEndArray();
	} else if (value instanceof float[]) {
		generator.writeStartArray();
		for (float v : (float[]) value) {
			generator.writeNumber(v);
		}
		generator.writeEndArray();
	} else if (value instanceof short[]) {
		generator.writeStartArray();
		for (short v : (short[]) value) {
			generator.writeNumber(v);
		}
		generator.writeEndArray();
	} else {
		// if this is a "value" object, like enum, DistanceUnit, ..., just toString it
		// yea, it can be misleading when toString a Java class, but really, jackson should be used in that case
		generator.writeString(value.toString());
		//throw new ElasticsearchIllegalArgumentException("type not supported for generic value conversion: " + type);
	}
}

我们看下这部分:XContentBuilder.defaultDatePrinter.print(((Date) value).getTime()) 进去后。看到如下:

/**
 * Prints a millisecond instant to a String.
 * <p>
 * This method will use the override zone and the override chronology if
 * they are set. Otherwise it will use the ISO chronology and default zone.
 *
 * @param instant  millis since 1970-01-01T00:00:00Z
 * @return the printed result
 */
public String print(long instant) {
	StringBuilder buf = new StringBuilder(requirePrinter().estimatePrintedLength());
	try {
		printTo((Appendable) buf, instant);
	} catch (IOException ex) {
		// StringBuilder does not throw IOException
	}
	return buf.toString();
}

看到这里就明白了吧。他最终的输出方式都是以字符串输出,只是默认的格式是:1970-01-01T00:00:00Z ,也就是默认的 UTC 格式。我的时间转换结果成:2016-07-04T03:03:12.616Z 这里并且有时区的概念,东八区,这里输出的时间少了8 个小时。这个得注意。

总结了下。最终输出都是String 类型。感觉不友好。我本想的是,我不管存入是怎么样,我取出来得是Date 对象就可以了。

官网时间(Date)格式说明

关于时间类型说明:https://www.elastic.co/guide/en/elasticsearch/reference/current/date.html

关于时间类型格式化:https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-date-format.html#strict-date-time

JSON doesn’t have a date datatype, so dates in Elasticsearch can either be:

  • strings containing formatted dates, e.g. "2015-01-01" or "2015/01/01 12:10:30".
  • a long number representing milliseconds-since-the-epoch.
  • an integer representing seconds-since-the-epoch.

Internally, dates are converted to UTC (if the time-zone is specified) and stored as a long number representing milliseconds-since-the-epoch.

Date formats can be customised, but if no format is specified then it uses the default:

"strict_date_optional_time||epoch_millis"

This means that it will accept dates with optional timestamps, which conform to the formats supported by strict_date_optional_time or milliseconds-since-the-epoch.

解决方法及问题:

1.时间输出格式,如果是默认 UTC  格式,时间不是我们常用的格式,而且时区问题,少了8个小时。

    解决方案:

  • 直接用毫秒值,缺点为不直观。

  • 直接设置format为你想要的格式,比如“yyyy-MM-dd HH:mm:ss” 然后存储的时候,指定格式,并且 Mapping  也是指定相同的format

2.存储Date,和取出来也是Dete?

    解决方案:

好了上面观点纯属个人观点。可能存在错误和参杂个人色彩。请勿作为直接参考。错误的地方,请在下面留言。


版权所属:SO JSON在线解析

原文地址:https://www.sojson.com/blog/149.html

转载时必须以链接形式注明原始出处及本声明。

本文主题:

如果本文对你有帮助,那么请你赞助我,让我更有激情的写下去,帮助更多的人。

关于作者
一个低调而闷骚的男人。
相关文章
Elasticsearch 教程,Elasticsearch 日期查询详解,Elasticsearch Date 查询Java API
Elasticsearch教程(六) elasticsearch Client创建
Elasticsearch教程(五) elasticsearch Mapping的创建
Elasticsearch教程 ,Elasticsearch count 查询,Elasticsearch 查询是否存在
Elasticsearch教程,Elasticsearch配置文件 — elasticsearch.yml
Elasticsearch教程(八) elasticsearch delete 删除数据(Java)
Elasticsearch 教程,Elasticsearch部署阿里云集群,支持外网请求方式
Elasticsearch教程,Elasticsearch Java API创建Mapping,指定分词器
Elasticsearch 分词,Elasticsearch Java API 分词 操作
Elasticsearch权威指南-中文.pdf,Elasticsearch 中文文档下载
最新文章
PHP变量剖析 4
SQL全外连接剖析 119
SQL自然连接剖析 147
springboot启动原理 245
SQL右连接【RIGHT JOIN】详解及图解 450
SQL左链接【LEFT JOIN】详解及图解 357
SQL非等值连接剖析 262
SQL等链接剖析 291
SQL内连接详解及图解 385
python之numpy常用的100种数值相关方法及代码示例 231
最热文章
最新MyEclipse8.5注册码,有效期到2020年 (已经更新) 679222
苹果电脑Mac怎么恢复出厂系统?苹果系统怎么重装系统? 674561
免费天气API,全国天气 JSON API接口,可以获取五天的天气预报 599008
免费天气API,天气JSON API,不限次数获取十五天的天气预报 565182
Jackson 时间格式化,时间注解 @JsonFormat 用法、时差问题说明 551699
我为什么要选择RabbitMQ ,RabbitMQ简介,各种MQ选型对比 509186
Elasticsearch教程(四) elasticsearch head 插件安装和使用 479635
Jackson 美化输出JSON,优雅的输出JSON数据,格式化输出JSON数据... ... 262798
Java 信任所有SSL证书,HTTPS请求抛错,忽略证书请求完美解决 244092
Elasticsearch教程(一),全程直播(小白级别) 225115
支付扫码

所有赞助/开支都讲公开明细,用于网站维护:赞助名单查看

查看我的收藏

正在加载... ...