您的位置:首页 > 其它

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

2016-07-04 23:14 405 查看
从昨晚开始,到今天中午之前,一直在纠结时间存储问题,昨晚是纠结时间取出来的问题。

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

但是发现好像不行。

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



//...省略部分代码

.startObject("create_date").field("type","date").field("format","yyyy-MM-ddHH:mm:ss").endObject()

//...省略部分代码

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



message[MapperParsingException[failedtoparse[create_date]];nested:IllegalArgumentException[Invalidformat:"2016-07-04T03:03:12.616Z"ismalformedat"T03:03:12.616Z"];]

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



result.put("create_date",newSimpleDateFormat("yyyy-MM-ddHH:mm:ss").format(create_date));

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

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



privatevoidwriteValue(Objectvalue)throwsIOException{

if(value==null){

generator.writeNull();

return;

}

Class<?>type=value.getClass();

if(type==String.class){

generator.writeString((String)value);

}elseif(type==Integer.class){

generator.writeNumber(((Integer)value).intValue());

}elseif(type==Long.class){

generator.writeNumber(((Long)value).longValue());

}elseif(type==Float.class){

generator.writeNumber(((Float)value).floatValue());

}elseif(type==Double.class){

generator.writeNumber(((Double)value).doubleValue());

}elseif(type==Byte.class){

generator.writeNumber(((Byte)value).byteValue());

}elseif(type==Short.class){

generator.writeNumber(((Short)value).shortValue());

}elseif(type==Boolean.class){

generator.writeBoolean(((Boolean)value).booleanValue());

}elseif(type==GeoPoint.class){

generator.writeStartObject();

generator.writeNumberField("lat",((GeoPoint)value).lat());

generator.writeNumberField("lon",((GeoPoint)value).lon());

generator.writeEndObject();

}elseif(valueinstanceofMap){

writeMap((Map)value);

}elseif(valueinstanceofPath){

//PathimplementsIterable<Path>andcausesendlessrecursionandaStackOverFlowiftreatedasanIterablehere

generator.writeString(value.toString());

}elseif(valueinstanceofIterable){

generator.writeStartArray();

for(Objectv:(Iterable<?>)value){

writeValue(v);

}

generator.writeEndArray();

}elseif(valueinstanceofObject[]){

generator.writeStartArray();

for(Objectv:(Object[])value){

writeValue(v);

}

generator.writeEndArray();

}elseif(type==byte[].class){

generator.writeBinary((byte[])value);

/*注意这里:如果是Date类型,就是以字符串输出。

如果你跟进去看。代码在下个片段。

*/

}elseif(valueinstanceofDate){

generator.writeString(XContentBuilder.defaultDatePrinter.print(((Date)value).getTime()));

}elseif(valueinstanceofCalendar){

generator.writeString(XContentBuilder.defaultDatePrinter.print((((Calendar)value)).getTimeInMillis()));

}elseif(valueinstanceofReadableInstant){

generator.writeString(XContentBuilder.defaultDatePrinter.print((((ReadableInstant)value)).getMillis()));

}elseif(valueinstanceofBytesReference){

BytesReferencebytes=(BytesReference)value;

if(!bytes.hasArray()){

bytes=bytes.toBytesArray();

}

generator.writeBinary(bytes.array(),bytes.arrayOffset(),bytes.length());

}elseif(valueinstanceofBytesRef){

BytesRefbytes=(BytesRef)value;

generator.writeBinary(bytes.bytes,bytes.offset,bytes.length);

}elseif(valueinstanceofText){

Texttext=(Text)value;

if(text.hasBytes()&&text.bytes().hasArray()){

generator.writeUTF8String(text.bytes().array(),text.bytes().arrayOffset(),text.bytes().length());

}elseif(text.hasString()){

generator.writeString(text.string());

}else{

BytesArraybytesArray=text.bytes().toBytesArray();

generator.writeUTF8String(bytesArray.array(),bytesArray.arrayOffset(),bytesArray.length());

}

}elseif(valueinstanceofToXContent){

((ToXContent)value).toXContent(this,ToXContent.EMPTY_PARAMS);

}elseif(valueinstanceofdouble[]){

generator.writeStartArray();

for(doublev:(double[])value){

generator.writeNumber(v);

}

generator.writeEndArray();

}elseif(valueinstanceoflong[]){

generator.writeStartArray();

for(longv:(long[])value){

generator.writeNumber(v);

}

generator.writeEndArray();

}elseif(valueinstanceofint[]){

generator.writeStartArray();

for(intv:(int[])value){

generator.writeNumber(v);

}

generator.writeEndArray();

}elseif(valueinstanceoffloat[]){

generator.writeStartArray();

for(floatv:(float[])value){

generator.writeNumber(v);

}

generator.writeEndArray();

}elseif(valueinstanceofshort[]){

generator.writeStartArray();

for(shortv:(short[])value){

generator.writeNumber(v);

}

generator.writeEndArray();

}else{

//ifthisisa"value"object,likeenum,DistanceUnit,...,justtoStringit

//yea,itcanbemisleadingwhentoStringaJavaclass,butreally,jacksonshouldbeusedinthatcase

generator.writeString(value.toString());

//thrownewElasticsearchIllegalArgumentException("typenotsupportedforgenericvalueconversion:"+type);

}

}

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



/**

*PrintsamillisecondinstanttoaString.

*<p>

*Thismethodwillusetheoverridezoneandtheoverridechronologyif

*theyareset.OtherwiseitwillusetheISOchronologyanddefaultzone.

*

*@paraminstantmillissince1970-01-01T00:00:00Z

*@returntheprintedresult

*/

publicStringprint(longinstant){

StringBuilderbuf=newStringBuilder(requirePrinter().estimatePrintedLength());

try{

printTo((Appendable)buf,instant);

}catch(IOExceptionex){

//StringBuilderdoesnotthrowIOException

}

returnbuf.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

JSONdoesn’thaveadatedatatype,sodatesinElasticsearchcaneitherbe:

stringscontainingformatteddates,e.g."2015-01-01"or"2015/01/0112:10:30".

alongnumberrepresentingmilliseconds-since-the-epoch.

anintegerrepresentingseconds-since-the-epoch.

Internally,datesareconvertedtoUTC(ifthetime-zoneisspecified)andstoredasalongnumberrepresentingmilliseconds-since-the-epoch.

Dateformatscanbecustomised,butifnoformatisspecifiedthenitusesthedefault:



"strict_date_optional_time||epoch_millis"

Thismeansthatitwillacceptdateswithoptionaltimestamps,whichconformtotheformatssupportedbystrict_date_optional_timeormilliseconds-since-the-epoch.

解决方法及问题:

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

解决方案:

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

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

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

解决方案:

存储的时候利用各种JSON对象,比如json-lib,fastjson,Jackson,gson等等。存储的时候就可以用JSONFormat一下再存储,然后取出来后,在用JSON.toBean(json,POJO.class),就解决了,这里利用的是相同JSON包转成JSON,然后又toBean回来,是没问题的,然后Elasticsearch也支持存储JSON。

好了上面观点纯属个人观点。可能存在错误和参杂个人色彩。请勿作为直接参考。错误的地方,请在下面留言。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: