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

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

但是发现好像不行。

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

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

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

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

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

  1. 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 行。

  1. private void writeValue(Object value) throws IOException {
  2. if (value == null) {
  3. generator.writeNull();
  4. return;
  5. }
  6. Class<?> type = value.getClass();
  7. if (type == String.class) {
  8. generator.writeString((String) value);
  9. } else if (type == Integer.class) {
  10. generator.writeNumber(((Integer) value).intValue());
  11. } else if (type == Long.class) {
  12. generator.writeNumber(((Long) value).longValue());
  13. } else if (type == Float.class) {
  14. generator.writeNumber(((Float) value).floatValue());
  15. } else if (type == Double.class) {
  16. generator.writeNumber(((Double) value).doubleValue());
  17. } else if (type == Byte.class) {
  18. generator.writeNumber(((Byte)value).byteValue());
  19. } else if (type == Short.class) {
  20. generator.writeNumber(((Short) value).shortValue());
  21. } else if (type == Boolean.class) {
  22. generator.writeBoolean(((Boolean) value).booleanValue());
  23. } else if (type == GeoPoint.class) {
  24. generator.writeStartObject();
  25. generator.writeNumberField("lat", ((GeoPoint) value).lat());
  26. generator.writeNumberField("lon", ((GeoPoint) value).lon());
  27. generator.writeEndObject();
  28. } else if (value instanceof Map) {
  29. writeMap((Map) value);
  30. } else if (value instanceof Path) {
  31. //Path implements Iterable<Path> and causes endless recursion and a StackOverFlow if treated as an Iterable here
  32. generator.writeString(value.toString());
  33. } else if (value instanceof Iterable) {
  34. generator.writeStartArray();
  35. for (Object v : (Iterable<?>) value) {
  36. writeValue(v);
  37. }
  38. generator.writeEndArray();
  39. } else if (value instanceof Object[]) {
  40. generator.writeStartArray();
  41. for (Object v : (Object[]) value) {
  42. writeValue(v);
  43. }
  44. generator.writeEndArray();
  45. } else if (type == byte[].class) {
  46. generator.writeBinary((byte[]) value);
  47. /* 注意这里:如果是Date类型,就是以字符串输出。
  48. 如果你跟进去看。代码在下个片段。
  49. */
  50. } else if (value instanceof Date) {
  51. generator.writeString(XContentBuilder.defaultDatePrinter.print(((Date) value).getTime()));
  52. } else if (value instanceof Calendar) {
  53. generator.writeString(XContentBuilder.defaultDatePrinter.print((((Calendar) value)).getTimeInMillis()));
  54. } else if (value instanceof ReadableInstant) {
  55. generator.writeString(XContentBuilder.defaultDatePrinter.print((((ReadableInstant) value)).getMillis()));
  56. } else if (value instanceof BytesReference) {
  57. BytesReference bytes = (BytesReference) value;
  58. if (!bytes.hasArray()) {
  59. bytes = bytes.toBytesArray();
  60. }
  61. generator.writeBinary(bytes.array(), bytes.arrayOffset(), bytes.length());
  62. } else if (value instanceof BytesRef) {
  63. BytesRef bytes = (BytesRef) value;
  64. generator.writeBinary(bytes.bytes, bytes.offset, bytes.length);
  65. } else if (value instanceof Text) {
  66. Text text = (Text) value;
  67. if (text.hasBytes() && text.bytes().hasArray()) {
  68. generator.writeUTF8String(text.bytes().array(), text.bytes().arrayOffset(), text.bytes().length());
  69. } else if (text.hasString()) {
  70. generator.writeString(text.string());
  71. } else {
  72. BytesArray bytesArray = text.bytes().toBytesArray();
  73. generator.writeUTF8String(bytesArray.array(), bytesArray.arrayOffset(), bytesArray.length());
  74. }
  75. } else if (value instanceof ToXContent) {
  76. ((ToXContent) value).toXContent(this, ToXContent.EMPTY_PARAMS);
  77. } else if (value instanceof double[]) {
  78. generator.writeStartArray();
  79. for (double v : (double[]) value) {
  80. generator.writeNumber(v);
  81. }
  82. generator.writeEndArray();
  83. } else if (value instanceof long[]) {
  84. generator.writeStartArray();
  85. for (long v : (long[]) value) {
  86. generator.writeNumber(v);
  87. }
  88. generator.writeEndArray();
  89. } else if (value instanceof int[]) {
  90. generator.writeStartArray();
  91. for (int v : (int[]) value) {
  92. generator.writeNumber(v);
  93. }
  94. generator.writeEndArray();
  95. } else if (value instanceof float[]) {
  96. generator.writeStartArray();
  97. for (float v : (float[]) value) {
  98. generator.writeNumber(v);
  99. }
  100. generator.writeEndArray();
  101. } else if (value instanceof short[]) {
  102. generator.writeStartArray();
  103. for (short v : (short[]) value) {
  104. generator.writeNumber(v);
  105. }
  106. generator.writeEndArray();
  107. } else {
  108. // if this is a "value" object, like enum, DistanceUnit, ..., just toString it
  109. // yea, it can be misleading when toString a Java class, but really, jackson should be used in that case
  110. generator.writeString(value.toString());
  111. //throw new ElasticsearchIllegalArgumentException("type not supported for generic value conversion: " + type);
  112. }
  113. }

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

  1. /**
  2. * Prints a millisecond instant to a String.
  3. * <p>
  4. * This method will use the override zone and the override chronology if
  5. * they are set. Otherwise it will use the ISO chronology and default zone.
  6. *
  7. * @param instant millis since 1970-01-01T00:00:00Z
  8. * @return the printed result
  9. */
  10. public String print(long instant) {
  11. StringBuilder buf = new StringBuilder(requirePrinter().estimatePrintedLength());
  12. try {
  13. printTo((Appendable) buf, instant);
  14. } catch (IOException ex) {
  15. // StringBuilder does not throw IOException
  16. }
  17. return buf.toString();
  18. }

看到这里就明白了吧。他最终的输出方式都是以字符串输出,只是默认的格式是: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:

  1. "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?

解决方案:

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

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

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

  1. java获取Date类型时间的前3个月,后3个月,前3天,后3天

    java获取Date类型时间的前3个月,后3个月,前3天,后3天 Calendar cal = Calendar.getInstance(); Date date = new Date(); cal. ...

  2. @JsonFormat Date类型时间 格式化 注解 使用

    前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家.点击跳转到教程. @JsonFormat注解是一个时间格式化注解,比如我们存储在mysql中的数据是date类型的,当 ...

  3. feign date类型时间错误问题

    问题 在feign传输date类型的数据时,在调用方时间正确,而被调用方获取时时间会相差14个小时. 原因 Feign客户端在进行通信时,会将Date类型对象转为String类型,如果这个时间是北京时 ...

  4. iBatis Date类型时间丢失问题

    下面只是解决了时间插入的问题,至于从数据库读书时间的问题,还需要经进一步. 参照下面的帖子 : http://code.google.com/a/eclipselabs.org/p/demo1/wik ...

  5. Date类型时间格式注解

    @ApiModelProperty(value = "生产日期") @DateTimeFormat(pattern = "yyyy-MM-dd") //后端-- ...

  6. 数据库里面date类型时间有时差,时区问题

    SpringBoot项目,mysql数据库 数据库的时区 show variables like "%time_zone%"; 阿里云的数据库 根据网上的资料,可以更改数据库的sy ...

  7. 全球机房遇到的 Date类型 比较时间区间解决方案

    日本机房展示: ************************日本机房**********************//查询当前时间对应的时区 mysql> show variables lik ...

  8. 数据库时间为datetime(date)类型,开发使用String类型的优劣

    随笔: 在mysql数据库中,关于时间的使用是datetime类型,而在开发中使用string类型 datetime类型是规范的格式,储存空间8 bytes,YYYY-MM-DD HH:MM:SS格式 ...

  9. Oracle date(时间)类型详解

    常用日期型数据类型         TIMESTAMP类型是DATE类型的一个扩展,DATE类型会存储年月日时分秒信息,TIMESTAMP类型精度更高,会存储到微秒.纳秒. 1.DATE 展示格式既可 ...

最新文章

  1. 美国《时代》周刊公布年度25大最佳发明名单
  2. H264格式具体说明
  3. C语言函数集(十七)
  4. hdu2722 简单最短路,处理好输入就行
  5. RIM发警告 部分黑莓手机存在安全漏洞
  6. ThreadLocal 中的ThreadLocalMap
  7. received packet with own address as source address
  8. 我们为何需要单点登录系统
  9. python 去除不可见字符\x00
  10. Qt文档阅读笔记-关于Q_DECLARE_METATYPE原理以及使用
  11. 【TensorFlow】TensorFlow从浅入深系列之一 -- 教你如何设置学习率(指数衰减法)
  12. String Algorithm
  13. Kaldi nnet3的fastlstm与标准LSTM
  14. [转]看懂 Serverless,这一篇就够了
  15. java 文件无法下载_无法从Java中的URL下载文件
  16. java poi 读取Excel中的手机号
  17. 如何测试5.1声卡测试软件,功能至上--德国坦克AUREON 5.1初步测试
  18. 开始学习机器学习之前你必须要了解的知识有哪些?机器学习系列入门篇
  19. 结巴分词,停用词生成词云图
  20. Dijkstra 路径规划算法原理详解及 Python 代码实现

热门文章

  1. java小程序知乎,微信小程序仿知乎实现评论留言功能
  2. Linux的任督二脉 进程调度和内存管理
  3. 微电子半导体集成电路专业术语英语整理
  4. 头对风,暖烘烘;脚对风,请郎中
  5. 卓普zp900s手机root和data大小调整经验
  6. 唐探、小说家、李焕英,哪一部贺岁档电影值得一看
  7. 蓝桥杯试题:神奇算式(C/C++)
  8. 有偏估计 无偏估计matlab,有偏估计和无偏估计
  9. c语言again的用法,重新开始:again用法小结
  10. 电商系统促销方案的设计