ES 中时间日期类型 “yyyy-MM-dd HH:mm:ss” 的完全避坑指南

这篇具有很好参考价值的文章主要介绍了ES 中时间日期类型 “yyyy-MM-dd HH:mm:ss” 的完全避坑指南。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1、ES中的日期类型有何不同

时间和日期类型是我们作为开发每天都会遇到的一种常见数据类型。和Java中有所不同,Elasticsearch 在索引创建之前并不是必须要创建索引的mapping。关系型数据库的思维就是在中写入数据之前,并不强制创建表结构。我们不用事先声明字段名称,字段类型以及长度等属性就可以直接像一个不存在的表中直接写入数据。

Elasticsearch把这种特性称之为dynamic mapping,也就是自动映射。Elasticsearch会根据你写入的字段的内容动态去判定字段的数据类型,不过这种自动映射的机制存在一些缺陷,比如在Elasticsearch中没有隐式类型转换,所以在自动映射的时候就会把字段映射为较宽的数据类型。比如你写入一个数字50,系统就会自动给你映射成long类型,而不是int 。一般企业中用于生产的环境都是使用手工映射,能保证按需创建以节省资源和达到更高的性能。

但是在Elasticsearch中,时间类型是一个非常容易踩坑的数据类型,通过一个例子向大家展示这个时间类型到底有多“坑”!

2、案例

2.1 案例介绍

假如我们有如下索引tax,保存了一些公司的纳税或资产信息,单位为“万元”。当然这里面的数据是随意填写的。多少为数据统计的时间,当前这个例子里。索引达的含义并不重要。关键点在于字段的内容格式。我们看到date字段其中包含了多种日期的格式:“yyyy-MM-dd”,“yyyy-MM-dd”还有时间戳。如果按照dynamic mapping,采取自动映射器来映射索引。我们自然而然的都会感觉字段应该是一个date类型。

POST tax/_bulk
{"index":{}}
{"date": "2021-01-25 10:01:12", "company": "中国烟草", "ratal": 5700000}
{"index":{}}
{"date": "2021-01-25 10:01:13", "company": "华为", "ratal": 4034113.182}
{"index":{}}
{"date": "2021-01-26 10:02:11", "company": "苹果", "ratal": 7784.7252}
{"index":{}}
{"date": "2021-01-26 10:02:15", "company": "小米", "ratal": 185000}
{"index":{}}
{"date": "2021-01-26 10:01:23", "company": "阿里", "ratal": 1072526}
{"index":{}}
{"date": "2021-01-27 10:01:54", "company": "腾讯", "ratal": 6500}
{"index":{}}
{"date": "2021-01-28 10:01:32", "company": "蚂蚁金服", "ratal": 5000}
{"index":{}}
{"date": "2021-01-29 10:01:21", "company": "字节跳动", "ratal": 10000}
{"index":{}}
{"date": "2021-01-30 10:02:07", "company": "中国石油", "ratal": 18302097}
{"index":{}}
{"date": "1648100904", "company": "中国石化", "ratal": 32654722}
{"index":{}}
{"date": "2021-11-1 12:20:00", "company": "国家电网", "ratal": 82950000}

然而我们以上代码查看tax索引的mapping,会惊奇的发现date居然是一个text类型。这是为什么呢?

"properties" : {
  "date" : {
    "type" : "text",
    "fields" : {
      "keyword" : {
        "type" : "keyword",
        "ignore_above" : 256
      }
    }
  }
}

2.2 原理揭秘

原因就在于对时间类型的格式的要求是绝对严格的。要求必须是一个标准的UTC时间类型。上述字段的数据格式如果想要使用,就必须使用yyyy-MM-ddTHH:mm:ssZ格式(其中T个间隔符,Z代表 0 时区),以下均为错误的时间格式(均无法被自动映射器识别为日期时间类型):

  • yyyy-MM-dd HH:mm:ss
  • yyyy-MM-dd
  • 时间戳

注意:需要注意的是时间说是必须的时间格式,但是需要通过手工映射方式在索引创建之前指定为日期类型,使用自动映射器无法映射为日期类型。

3、路为何这么不平

我们现在已经知道要求其类型必须为UTC的时间格式,那么我们把下面索引通过自动映射,date字段会被映射为什么类型呢?

PUT test_index/_doc/1
{
  "time":"2022-4-30T20:00:00Z"
}

执行代码,我们来看一下结果:
es 时间类型,elasticsearch,es,分布式,数据库
历史总是惊人的相似,映射结果居然依然是文本类型。这就是又一个我们很容易踩的坑,日期字段并非严格符合要求格式。

注意观察下面两者区别:

  • 2022-4-30T20:00:00Z 错误
  • 2022-04-30T20:00:00Z 正确

应该不用再用我解释什么了吧 O(_)O哈哈~

4、又一个坑

你以为这样就结束了吗?

如果我们换一个思路,使用手工映射提前指定日期类型,那会又是一个什么结果呢?

PUT tax
{
  "mappings": {
    "properties": {
      "date": {
        "type": "date"
      }
    }
  }
}
POST tax/_bulk
{"index":{}}
{"date": "2021-01-30 10:02:07", "company": "中国石油", "ratal": 18302097}
{"index":{}}
{"date": "1648100904", "company": "中国石化", "ratal": 32654722}
{"index":{}}
{"date": "2021-11-1T12:20:00Z", "company": "国家电网", "ratal": 82950000}
{"index":{}}
{"date": "2021-01-30T10:02:07Z", "company": "中国石油", "ratal": 18302097}
{"index":{}}
{"date": "2021-01-25", "company": "中国烟草", "ratal": 5700000}

执行以上代码,以下为完整的执行结果:

{
  "took" : 17,
  "errors" : true,
  "items" : [
    {
      "index" : {
        "_index" : "tax",
        "_type" : "_doc",
        "_id" : "f4uyun8B1ovRQq6Sn9Qg",
        "status" : 400,
        "error" : {
          "type" : "mapper_parsing_exception",
          "reason" : "failed to parse field [date] of type [date] in document with id 'f4uyun8B1ovRQq6Sn9Qg'. Preview of field's value: '2021-01-30 10:02:07'",
          "caused_by" : {
            "type" : "illegal_argument_exception",
            "reason" : "failed to parse date field [2021-01-30 10:02:07] with format [strict_date_optional_time||epoch_millis]",
            "caused_by" : {
              "type" : "date_time_parse_exception",
              "reason" : "date_time_parse_exception: Failed to parse with all enclosed parsers"
            }
          }
        }
      }
    },
    {
      "index" : {
        "_index" : "tax",
        "_type" : "_doc",
        "_id" : "gIuyun8B1ovRQq6Sn9Qg",
        "_version" : 1,
        "result" : "created",
        "_shards" : {
          "total" : 2,
          "successful" : 2,
          "failed" : 0
        },
        "_seq_no" : 3,
        "_primary_term" : 1,
        "status" : 201
      }
    },
    {
      "index" : {
        "_index" : "tax",
        "_type" : "_doc",
        "_id" : "gYuyun8B1ovRQq6Sn9Qg",
        "status" : 400,
        "error" : {
          "type" : "mapper_parsing_exception",
          "reason" : "failed to parse field [date] of type [date] in document with id 'gYuyun8B1ovRQq6Sn9Qg'. Preview of field's value: '2021-11-1T12:20:00Z'",
          "caused_by" : {
            "type" : "illegal_argument_exception",
            "reason" : "failed to parse date field [2021-11-1T12:20:00Z] with format [strict_date_optional_time||epoch_millis]",
            "caused_by" : {
              "type" : "date_time_parse_exception",
              "reason" : "date_time_parse_exception: Failed to parse with all enclosed parsers"
            }
          }
        }
      }
    },
    {
      "index" : {
        "_index" : "tax",
        "_type" : "_doc",
        "_id" : "gouyun8B1ovRQq6Sn9Qg",
        "_version" : 1,
        "result" : "created",
        "_shards" : {
          "total" : 2,
          "successful" : 2,
          "failed" : 0
        },
        "_seq_no" : 4,
        "_primary_term" : 1,
        "status" : 201
      }
    },
    {
      "index" : {
        "_index" : "tax",
        "_type" : "_doc",
        "_id" : "g4uyun8B1ovRQq6Sn9Qg",
        "_version" : 1,
        "result" : "created",
        "_shards" : {
          "total" : 2,
          "successful" : 2,
          "failed" : 0
        },
        "_seq_no" : 5,
        "_primary_term" : 1,
        "status" : 201
      }
    }
  ]
}

分析:

  • 第一个(写入失败):2021-01-30 10:02:07
  • 第二个(写入成功):1648100904
  • 第三个(写入失败):2021-11-1T12:20:00Z
  • 第四个(写入成功):2021-01-30T10:02:07Z
  • 第五个(写入成功):2021-01-25

5、总结

  • 对于yyyy-MM-dd HH:mm:ss2021-11-1T12:20:00Z,ES 的自动映射器完全无法识别,即便是事先声明日期类型,数据强行写入也会失败。
  • 对于时间戳yyyy-MM-dd这样的时间格式,ES 自动映射器无法识别,但是如果事先说明了日期类型是可以正常写入的。
  • 对于标准的日期时间类型是可以正常自动识别为日期类型,并且也可以通过手工映射来实现声明字段类型。

6、ES 的时间类型为什么这么难用,有没有什么办法可以解决?

有,当然有,必须有,关注我就对了 😃

其实解决办法非常简单。只需要在字段属性中添加一个参数:

"format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis",这样就可以避免因为数据格式不统一而导致数据无法写入的窘境。代码如下:

PUT test_index
{
  "mappings": {
    "properties": {
      "time": {
        "type": "date",
        "format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis"
      }
    }
  }
}

7、更优的生产解决方案

那么问题来了,如果我们生产环境中的数据已经是text类型,无法按照时间进行检索,只能Reindex吗?

当然不是!那样也太Low了!更优解决方案,推荐阅读:不必Reindex,利用runtime_fields优雅地解决字段类型错误问题

这么干货,还不赶快分享与点赞!

加入Elastic开源社区,更多原创干货与你分享!文章来源地址https://www.toymoban.com/news/detail-818107.html

到了这里,关于ES 中时间日期类型 “yyyy-MM-dd HH:mm:ss” 的完全避坑指南的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • yyyy-MM-dd HH:mm:ss 时间格式 时间戳 全面解读超详细

    时间格式(协议) 描述 gg 时期或纪元。 y 不包含纪元的年份。不具有前导零。 yy 不包含纪元的年份。具有前导零。 yyyy 包含纪元的四位数的年份。 M 月份数字。一位数的月份没有前导零。 MM 月份数字。一位数的月份有一个前导零。 MMM 月份的缩写名称,在AbbreviatedMonthNames中定

    2024年02月05日
    浏览(41)
  • 踩坑:小程序 new Date(“YYYY-MM-DD hh:mm:ss”)在ios手机上显示null

    一、发现问题: 苹果手机上进入小程序,点击picker组件选择时间日期(YYYY-MM-DD hh:mm:ss),用new Date(“YYYY-MM-DD hh:mm:ss”)转化时间格式进行比较时,变量转化后的结果为null 二、解决方案: 三、分析并查找原因: 1.在IOS中,new Date中指定的字符串还有格式,new Date(“YYYY/MM/DD hh:

    2024年02月12日
    浏览(36)
  • yyyy-MM-dd‘T‘HH:mm:ssZ的T是什么意思?为什么要用单引号引着

    背景 Java里的日期格式,通常我们看到 yyyy-MM-dd\\\'T\\\'HH:mm:ssZ 的写法是什么意思? 尤其这个T作为分隔符为什么左右有单引号,这个单引号会打印出来吗? 这个Z又是什么意思?是时区吗?如果是时区,输出的格式是什么?是类似于这样的字符串:+0800还是+08:00还是+8:00? 解释 yyyy-

    2024年02月07日
    浏览(35)
  • 直接在SQL中对日期格式进行转换yyyy/MM/dd到yyyy-MM-dd【DATE_FORMAT()】

    可以直接在SQL中转换日期的格式会使用到DATE_FORMAT()使用函数 DATE_FORMAT()函数中需要输入两个参数:原本的日期和你期待的模式字符串 例如:我们要将2022/05/09的字符串转换成2022-05-09的格式,就可以用以下两种方式 ①:SELECT DATE_FORMAT(\\\'2022/05/09\\\',\\\'20%y-%m-%d\\\') DATE; ②:SELECT DATE_FO

    2023年04月18日
    浏览(52)
  • 【夏令时】用@JsonFormat(pattern = “yyyy-MM-dd“)注解,出生日期竟然年轻了一天

    用@JsonFormat(pattern = \\\"yyyy-MM-dd\\\")注解,出生日期竟然年轻了一天 艺术源于生活,bug源于开发。 起因是艰苦奋战一个月, 测试及验收都顺利通过 ,上线也稳稳的 成功 。但是 毒奶 总是在不经意给你灌上,部分的用户的 身份证和出生日期对不上,总是少一天 。 开始以为 前端显

    2024年02月11日
    浏览(40)
  • JS日期与字符串相互转换(时间格式化YYYY-MM-DD,Dayjs的使用)

    文章内容 文章链接 JS数组对象—— 根据日期进行排序 , 按照时间进行升序或降序排序 https://blog.csdn.net/XSL_HR/article/details/128579840?spm=1001.2014.3001.5501 JS日期时间格式化—— 数字日期转中文日期 (封装函数,dayjs转换时间格式) https://blog.csdn.net/XSL_HR/article/details/128607024?spm=100

    2024年01月18日
    浏览(77)
  • 致命小问题:YYYY-MM-dd格式化时间

    日期格式化可以说是最常用的一个小知识了,例如格式化成\\\" 年-月-日 \\\"、\\\" 年-月-日 时-分-秒 \\\"、“ 年/月/日 ”等等,随之也就出现了“ yyyy-MM-dd ”、\\\" yyyy-MM-dd HH-mm-ss \\\"等格式,使用不当就会一脸懵逼。 首先将日期改为 2019 看一下运行效果: 其次将日期改为 2022 再看一下运行

    2024年02月05日
    浏览(46)
  • 前端 jQuery 如何将时间转换为yyyy-MM-dd格式的

    可以使用 JavaScript 内置的 Date 对象和其提供的方法来实现将时间转换为指定格式的字符串。具体可以使用以下代码: 上述代码中,我们首先创建了一个 Date 对象,然后使用其提供的 getFullYear() 、 getMonth() 和 getDate() 方法获取了年份、月份和日期。注意, getMonth() 方法返回的月

    2024年02月06日
    浏览(43)
  • Js各种时间转换问题(YYYY-MM-DD 时间戳 中国标准时间)

    指定格式 YYYY-MM-DD HH:MM:SS 时间戳 中国标准时间 Sat Jan 30 2022 08:26:26 GMT+0800 (中国标准时间) new Date() 获得系统当前时间就会是这种形式 时间戳转换为 yyyy-mm-dd或yyyy-MM-dd HH-mm-ss yyyy-mm-dd或yyyy-MM-dd HH-mm-ss 转为时间戳 中国标准时间转为 yyyy-mm-dd hh-mm-ss yyyy-mm-dd hh-mm-ss 转为中国标准时间

    2024年01月21日
    浏览(40)
  • Aspose.cell excel转pdf日期格式不正确yyyy/MM/dd变成MM/dd/yyyy

    最近使用Aspose.cell将excel转pdf过程中excel中时间格式列的显示和excel表里的值显示不一样。 excel里日期格式 yyyy/MM/dd pdf里日期格式MM/dd/yyyy 主要原因:linux和windows里内置的时间格式不一致,当代码部署到linux服务器的时候转换格式就会发生不一致的问题。 解决方法:使用apache p

    2024年02月15日
    浏览(39)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包