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对象就可以了。
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.
直接用毫秒值,缺点为不直观。
直接设置format为你想要的格式,比如“yyyy-MM-ddHH:mm:ss”然后存储的时候,指定格式,并且Mapping也是指定相同的format。
存储的时候利用各种JSON对象,比如json-lib,fastjson,Jackson,gson等等。存储的时候就可以用JSONFormat一下再存储,然后取出来后,在用JSON.toBean(json,POJO.class),就解决了,这里利用的是相同JSON包转成JSON,然后又toBean回来,是没问题的,然后Elasticsearch也支持存储JSON。
好了上面观点纯属个人观点。可能存在错误和参杂个人色彩。请勿作为直接参考。错误的地方,请在下面留言。
其实我的想法很简单,我就想
但是发现好像不行。
我开始在创建
指定了
根据错误提示,我先把时间格式化,然后插入:
然后插入OK。后来我看了源码,才恍然大悟。新版本(我不知道从什么版本开始,我以前最开始用的是0.9)值是根据value的类型来判断。我贴一下。
我们看下这部分:
看到这里就明白了吧。他最终的输出方式都是以字符串输出,只是默认的格式是:
总结了下。最终输出都是
官网时间(Date)格式说明
关于时间类型说明:关于时间类型格式化:
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,whichconformtotheformatssupportedby
解决方法及问题:
1.时间输出格式,如果是默认UTC格式,时间不是我们常用的格式,而且时区问题,少了8个小时。
解决方案:直接用毫秒值,缺点为不直观。
直接设置format为你想要的格式,比如
2.存储Date,和取出来也是Dete?
解决方案:存储的时候利用各种JSON对象,比如
好了上面观点纯属个人观点。可能存在错误和参杂个人色彩。请勿作为直接参考。错误的地方,请在下面留言。
相关文章推荐
- 备忘
- 4.1.6 文件系统基础
- 模板方法模式(学习于 php设计模式 书 )
- softmax分类
- noip 2010 关押罪犯
- Shell 编程之if常见语法
- mac os mysql启动报错 Can't open the mysql.plugin table
- mysql修改 utf8mb4编码
- 宏定义中#和##的使用
- 利用HTML和CSS实现常见的布局
- mysql自动备份
- Forge手机在线源安装流程
- c#自定义条件排序 可以使用中文条件 datagirdview
- (转)CentOS下开机启动查看管理命令:chkconfig用法
- 后端接收不到AngularJs中$http.post发送的数据的问题
- 由浅入深理解闭包的运行机制
- mysql乱码
- Objective-C面向对象初步归纳
- struts2文件下载
- hive-导出数据的方式