ElasticSearch时间类型的坑!究竟如何选择使用的格式?

ElasticSearch时间类型的坑!究竟如何选择使用的格式?

在使用 ElasticSearch 作为数据存储时,日期字段常常是我们进行查询和分析的关键数据之一。尤其是在处理时间戳时,ElasticSearch 提供了灵活的时间格式支持,可以处理多种不同的时间格式。本文将探讨当设置多个时间格式时,ElasticSearch 是如何决定使用哪个格式的,并分析可能出现的潜在问题。

ElasticSearch 时间字段的定义

ElasticSearch 中,时间字段通常会定义为 date 类型。这种类型允许我们指定时间格式,帮助 ElasticSearch 解析并存储时间数据。通过 mappings 来定义时间字段时,可以指定一个或多个时间格式。

支持的常用时间格式

ElasticSearch 支持多种时间格式,使得我们可以方便地处理各种不同来源的数据。常见的几种时间格式包括:

1. yyyy-MM-dd HH:mm:ss

这种格式表示一个具体的时间点,包括年月日、小时、分钟、秒。例如,2022-03-15 12:30:45

2. yyyy-MM-dd

这种格式只包含年月日,不包括具体的时间部分。例如,2022-03-15

3. epoch_millis

epoch_millis 表示毫秒级的时间戳,指从 1970-01-01 00:00:00 UTC 到当前时间的毫秒数。例如,1672531200000 表示 2023-01-01 00:00:00 UTC

4. epoch_second

epoch_second 表示秒级的时间戳,指从 1970-01-01 00:00:00 UTC 到当前时间的秒数。例如,1672531200 表示 2023-01-01 00:00:00 UTC

如何设置多个格式

在 ElasticSearch 中,可以通过在 mappings 中为日期字段指定多个格式,来支持不同的时间表示方式。通过使用 || 运算符,可以将多个格式结合起来,ElasticSearch 会尝试按顺序匹配每个格式。

以下是一个完整的例子,展示了如何为日期字段设置多个格式:

在这里插入图片描述

在这个配置中这个字段支持了四种时间格式:

  1. yyyy-MM-dd HH:mm:ss
  2. yyyy-MM-dd
  3. epoch_millis(毫秒级时间戳)
  4. epoch_second(秒级时间戳)

ElasticSearch 如何选择时间格式

那么如果当我们写入一个时间戳,到底使用的是epoch_millis还是epoch_second呢?

在这里很多朋友可能说,10 位的时间戳是epoch_second秒级时间戳,13 位的是epoch_millis毫秒级时间戳。

那么问题来了,当我们写入 1 时,它算哪个类型呢?

先说结论:实际它不是按照位数判断的,当向 ElasticSearch 中写入时间数据时,它会按照配置的格式顺序进行匹配,找到第一个符合格式的规则进行解析。

我们来实际验证一下

写入一条数据

POST /example_index/_doc
{
  "first_login_time": 1672531200
}

查看数据(这里我们通过 script 方式自动转换时间)

GET /example_index/_search
{
  "_source": {
    "includes": ["first_login_time"]
  },
  "script_fields": {
    "formatted_time": {
      "script": {
        "source": """
          DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").withZone(ZoneOffset.UTC);
          return formatter.format(Instant.ofEpochMilli(doc['first_login_time'].value.millis));
        """
      }
    }
  }
}

结果我们发现,它是按照毫秒单位写入的,这也就验证了刚刚的结论,按照我们设置的 format 顺序进行的匹配。

{
        "_index" : "example_index",
        "_type" : "_doc",
        "_id" : "9r2WbZQBpX9FjWS70nx1",
        "_score" : 1.0,
        "_source" : {
          "first_login_time" : 1672531200
        },
        "fields" : {
          "formatted_time" : [
            "1970-01-20 08:35:31"
          ]
        }
      }

按照这个逻辑,发现epoch_second类型永远无法触发,想了下如果反过来配置呢?

按照这个格式创建字段yyyy-MM-dd HH:mm:ss || yyyy-MM-dd || epoch_second || epoch_millis,写入毫秒的时间戳。

发现结果为+33658-09-27 01:46:40,也同样无法按照毫秒级写入。

在这里插入图片描述

潜在问题与结论

经过实际验证,我们发现,ElasticSearch 在同时设置 epoch_secondepoch_millis 时,始终会选择第一个匹配的格式。因此,如果你同时设置这两个格式,后面的配置(如 epoch_millis)将不会生效。这个行为可能是 ElasticSearch 的一个潜在 Bug,用户在配置多个时间格式时应避免同时使用 epoch_secondepoch_millis

解决方案:

  1. 如果需要使用秒级时间戳,请仅配置 epoch_second
  2. 如果需要使用毫秒级时间戳,请仅配置 epoch_millis
  3. 避免同时配置这两个选项。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值