Java 时间迁移指南

编辑

在 7.0 版本中,Elasticsearch 将日期相关的解析、格式化和计算从 joda time 切换到了 java time。本指南旨在帮助您确定您的集群是否受到影响,如果受到影响,则帮助您为升级做好准备。

转换日期格式

编辑

要升级到 Elasticsearch 8,您需要将任何 joda-time 日期格式转换为其 java-time 等效格式。

受影响的功能

编辑

切换到 java time 仅影响自定义 datedate_nanos 格式。

这些格式通常用于

如果您不使用自定义日期格式,则可以跳过本指南的其余部分。大多数自定义日期格式都是兼容的。但是,有几个需要更新。

要查看您的日期格式是否受到影响,请使用 弃用信息 APIKibana 升级助手

不兼容的日期格式

编辑

应迁移包含以下 joda-time 字面量的自定义日期格式。

Y(年代年份)

替换为 y

示例: YYYY-MM-dd 应变为 yyyy-MM-dd

在 java time 中,Y 用于基于周的年份。在 y 的位置使用 Y 可能会导致年份计算中出现一位的误差。

对于模式 YYYY-ww 和日期 2019-01-01T00:00:00.000Z 将给出 2019-01。对于模式 YYYY-ww 和日期 2018-12-31T00:00:00.000Z 将给出 2019-01(违反直觉),因为 2019 年该周的日期有超过 4 天。

y(年份)

替换为 u

示例: yyyy-MM-dd 应变为 uuuu-MM-dd

在 java time 中,y 用于年代年份。u 可以包含非正值,而 y 不能。y 还可以与年代字段关联。

C(年代世纪)

java time 中不支持年代世纪。没有替换项。相反,我们建议您预处理输入。

x(周年份)

替换为 Y

在 java time 中,x 表示 时区偏移量

未能正确将 x(周年份)转换为 Y 可能会导致数据丢失。

Z(时区偏移量/ID)

替换为多个 X

Z 在 java time 中具有相似的含义。但是,java time 需要不同数量的字面量来解析不同的形式。

考虑迁移到 X,这样您可以更好地控制时间的解析方式。例如,joda-time 格式 YYYY-MM-dd'T'hh:mm:ssZZ 接受以下日期

2010-01-01T01:02:03Z
2010-01-01T01:02:03+01
2010-01-01T01:02:03+01:02
2010-01-01T01:02:03+01:02:03

在 java time 中,您不能使用单个格式解析所有这些日期。相反,您必须指定 3 种单独的格式

2010-01-01T01:02:03Z
2010-01-01T01:02:03+01
both parsed with yyyy-MM-dd'T'hh:mm:ssX

2010-01-01T01:02:03+01:02
yyyy-MM-dd'T'hh:mm:ssXXX

2010-01-01T01:02:03+01:02:03
yyyy-MM-dd'T'hh:mm:ssXXXXX

然后必须使用 || 分隔这些格式

yyyy-MM-dd'T'hh:mm:ssX||yyyy-MM-dd'T'hh:mm:ssXXX||yyyy-MM-dd'T'hh:mm:ssXXXXX

如果您期望模式出现在没有冒号 (:) 的情况下,则同样适用:例如,YYYY-MM-dd'T'hh:mm:ssZ 格式接受以下日期形式

2010-01-01T01:02:03Z
2010-01-01T01:02:03+01
2010-01-01T01:02:03+0102
2010-01-01T01:02:03+010203

要接受 java time 中的所有这些形式,您必须使用 || 分隔符

yyyy-MM-dd'T'hh:mm:ssX||yyyy-MM-dd'T'hh:mm:ssXX||yyyy-MM-dd'T'hh:mm:ssXXXX
d(天)

在 java time 中,d 仍然被解释为“天”,但灵活性较差。

例如,joda-time 日期格式 YYYY-MM-dd 接受 2010-01-012010-01-1

在 java time 中,您必须使用 || 分隔符来指定每种格式

yyyy-MM-dd||yyyy-MM-d

在 java time 中,d 也不接受超过 2 位数字。要接受超过两位数字的天数,您必须在 java-time 日期格式中包含文本字面量。例如,要解析 2010-01-00001,您必须使用以下 java-time 日期格式

yyyy-MM-'000'dd
e(星期几的名称)

在 java time 中,e 仍然被解释为“星期几的名称”,但不解析短文本或全文形式。

例如,joda-time 日期格式 EEE YYYY-MM 接受 Wed 2020-01Wednesday 2020-01

要在 java time 中接受这两种日期,您必须使用 || 分隔符指定每种格式

cccc yyyy-MM||ccc yyyy-MM

joda-time 字面量 E 被解释为“星期几”。java-time 字面量 c 被解释为“本地化的星期几”。E 不接受全文的星期格式,例如 Wednesday

EEEE 和类似的文本形式

对全文形式的支持取决于 Java 开发工具包 (JDK) 提供的区域设置数据和其他实现细节。我们建议您在升级之前仔细测试包含这些模式的格式。

z(时区文本)

在 java time 中,当给定 UTC 时区时,z 会为 Zulu 输出 Z

使用您的数据进行测试

编辑

我们强烈建议您在生产环境中部署之前,使用真实数据测试任何日期格式更改。

更新索引映射

编辑

要在索引映射中更新 joda-time 日期格式,您必须创建一个具有更新映射的新索引,并将您的数据重新索引到该索引。

以下 my-index-000001 索引包含 datetime 字段的映射,这是一个带有自定义 joda-time 日期格式的 date 字段。

resp = client.indices.get_mapping(
    index="my-index-000001",
)
print(resp)
response = client.indices.get_mapping(
  index: 'my-index-000001'
)
puts response
const response = await client.indices.getMapping({
  index: "my-index-000001",
});
console.log(response);
GET my-index-000001/_mapping
{
  "my-index-000001" : {
    "mappings" : {
      "properties" : {
         "datetime": {
           "type": "date",
           "format": "yyyy/MM/dd HH:mm:ss||yyyy/MM/dd||epoch_millis"
         }
      }
    }
  }
}

要更改 datetime 字段的日期格式,请创建一个单独的索引,其中包含更新的映射和日期格式。

例如,以下 my-index-000002 索引将 datetime 字段的日期格式更改为 uuuu/MM/dd HH:mm:ss||uuuu/MM/dd||epoch_millis

response = client.indices.create(
  index: 'my-index-000002',
  body: {
    mappings: {
      properties: {
        datetime: {
          type: 'date',
          format: 'uuuu/MM/dd HH:mm:ss||uuuu/MM/dd||epoch_millis'
        }
      }
    }
  }
)
puts response
PUT my-index-000002
{
  "mappings": {
    "properties": {
      "datetime": {
        "type": "date",
        "format": "uuuu/MM/dd HH:mm:ss||uuuu/MM/dd||epoch_millis"
      }
    }
  }
}

接下来,将数据从旧索引重新索引到新索引。

以下 重新索引 API 请求将数据从 my-index-000001 重新索引到 my-index-000002

response = client.reindex(
  body: {
    source: {
      index: 'my-index-000001'
    },
    dest: {
      index: 'my-index-000002'
    }
  }
)
puts response
POST _reindex
{
  "source": {
    "index": "my-index-000001"
  },
  "dest": {
    "index": "my-index-000002"
  }
}

如果您使用索引别名,请更新它们以指向新索引。

POST /_aliases
{
  "actions" : [
    { "remove" : { "index" : "my-index-000001", "alias" : "my-index" } },
    { "add" : { "index" : "my-index-000002", "alias" : "my-index" } }
  ]
}