Java時間移行ガイド

Elasticsearchは7.0でjoda timeからjava timeに切り替え、日付関連の解析、フォーマット、および計算を行います。このガイドは、クラスターが影響を受けるかどうかを判断し、影響を受ける場合はアップグレードの準備をするのに役立つように設計されています。

日付フォーマットの変換

Elasticsearch 8にアップグレードするには、joda-timeの日付フォーマットをjava-timeの同等のものに変換する必要があります。

影響を受ける機能

java timeへの切り替えは、カスタムdateおよびdate_nanosフォーマットにのみ影響します。

これらのフォーマットは、以下で一般的に使用されます:

カスタム日付フォーマットを使用していない場合は、このガイドの残りをスキップできます。ほとんどのカスタム日付フォーマットは互換性があります。ただし、いくつかは更新が必要です。

日付フォーマットが影響を受けるかどうかを確認するには、非推奨情報APIまたはKibanaアップグレードアシスタントを使用してください。

互換性のない日付フォーマット

以下のjoda-timeリテラルを含むカスタム日付フォーマットは移行する必要があります。

  • Y (時代の年)
  • yに置き換えます。
    例: YYYY-MM-ddyyyy-MM-ddに変わるべきです。
    java timeでは、Y週ベースの年に使用されます。Yyの代わりに使用すると、年の計算でオフバイワンエラーが発生する可能性があります。
    パターンYYYY-wwと日付2019-01-01T00:00:00.000Z2019-01を返します。パターンYYYY-wwと日付2018-12-31T00:00:00.000Z2019-01を返します(直感に反する)なぜなら、2019年のその週には4日以上あるからです。
  • y (年)
  • uに置き換えます。
    例: yyyy-MM-dduuuu-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は異なる形式を解析するために異なる数のリテラルを期待します。
    1. ``````bash
    2. 2010-01-01T01:02:03Z
    3. 2010-01-01T01:02:03+01
    4. 2010-01-01T01:02:03+01:02
    5. 2010-01-01T01:02:03+01:02:03
    6. `
    java timeでは、これらすべての日付を単一のフォーマットで解析することはできません。代わりに、3つの別々のフォーマットを指定する必要があります:
    ``````bash
    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

  1. フォーマットは`````||`````を使用して区切る必要があります:
  2. #### テキスト
  3. ``````txt
  4. 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フォーマットは次の日付形式を受け入れます:

  1. 2010-01-01T01:02:03Z
  2. 2010-01-01T01:02:03+01
  3. 2010-01-01T01:02:03+0102
  4. 2010-01-01T01:02:03+010203

これらすべての形式をjava timeで受け入れるには、||区切り文字を使用する必要があります:

テキスト

  1. 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-dd2010-01-01または2010-01-1を受け入れます。
    java timeでは、||区切り文字を使用して各フォーマットを指定する必要があります:

テキスト

  1. yyyy-MM-dd||yyyy-MM-d

java timeでは、dは2桁以上を受け入れません。2桁以上の日を受け入れるには、java-timeの日付フォーマットにテキストリテラルを含める必要があります。たとえば、2010-01-00001を解析するには、次のjava-timeの日付フォーマットを使用する必要があります:

テキスト

  1. yyyy-MM-'000'dd
  • e (曜日の名前)
  • java timeでは、eは依然として「曜日の名前」として解釈されますが、短縮形や完全なテキスト形式を解析しません。
    たとえば、joda-timeの日付フォーマットEEE YYYY-MMWed 2020-01Wednesday 2020-01の両方を受け入れます。
    これらの両方の日付をjava timeで受け入れるには、||区切り文字を使用して各フォーマットを指定する必要があります:

テキスト

  1. cccc yyyy-MM||ccc yyyy-MM

joda-timeリテラルEは「週の日」として解釈されます。java-timeリテラルcは「ローカライズされた週の日」として解釈されます。EWednesdayのような完全なテキストの日形式を受け入れません。

  • EEEEおよび類似のテキスト形式
  • 完全なテキスト形式のサポートは、Java Development Kit (JDK)と他の実装の詳細に提供されるロケールデータに依存します。アップグレード前に、これらのパターンを含むフォーマットを慎重にテストすることをお勧めします。
  • z (タイムゾーンテキスト)
  • java timeでは、zはUTCタイムゾーンが与えられた場合にZを出力します。

データでテスト

本番環境にデプロイする前に、実際のデータを使用して日付フォーマットの変更をテストすることを強くお勧めします。

インデックスマッピングの更新

インデックスマッピング内のjoda-timeの日付フォーマットを更新するには、更新されたマッピングを持つ新しいインデックスを作成し、データを再インデックスする必要があります。

以下のmy-index-000001インデックスには、datetimeフィールドのマッピングと、カスタムjoda-time日付フォーマットを持つdateフィールドが含まれています。

Python

  1. resp = client.indices.get_mapping(
  2. index="my-index-000001",
  3. )
  4. print(resp)

Ruby

  1. response = client.indices.get_mapping(
  2. index: 'my-index-000001'
  3. )
  4. puts response

Js

  1. const response = await client.indices.getMapping({
  2. index: "my-index-000001",
  3. });
  4. console.log(response);

コンソール

  1. GET my-index-000001/_mapping

コンソール結果

  1. {
  2. "my-index-000001" : {
  3. "mappings" : {
  4. "properties" : {
  5. "datetime": {
  6. "type": "date",
  7. "format": "yyyy/MM/dd HH:mm:ss||yyyy/MM/dd||epoch_millis"
  8. }
  9. }
  10. }
  11. }
  12. }
  1. たとえば、以下の`````my-index-000002`````インデックスは`````datetime`````フィールドの日付フォーマットを`````uuuu/MM/dd HH:mm:ss||uuuu/MM/dd||epoch_millis`````に変更します。
  2. #### Python
  3. ``````python
  4. resp = client.indices.create(
  5. index="my-index-000002",
  6. mappings={
  7. "properties": {
  8. "datetime": {
  9. "type": "date",
  10. "format": "uuuu/MM/dd HH:mm:ss||uuuu/MM/dd||epoch_millis"
  11. }
  12. }
  13. },
  14. )
  15. print(resp)
  16. `

Ruby

  1. response = client.indices.create(
  2. index: 'my-index-000002',
  3. body: {
  4. mappings: {
  5. properties: {
  6. datetime: {
  7. type: 'date',
  8. format: 'uuuu/MM/dd HH:mm:ss||uuuu/MM/dd||epoch_millis'
  9. }
  10. }
  11. }
  12. }
  13. )
  14. puts response

Js

  1. const response = await client.indices.create({
  2. index: "my-index-000002",
  3. mappings: {
  4. properties: {
  5. datetime: {
  6. type: "date",
  7. format: "uuuu/MM/dd HH:mm:ss||uuuu/MM/dd||epoch_millis",
  8. },
  9. },
  10. },
  11. });
  12. console.log(response);

コンソール

  1. PUT my-index-000002
  2. {
  3. "mappings": {
  4. "properties": {
  5. "datetime": {
  6. "type": "date",
  7. "format": "uuuu/MM/dd HH:mm:ss||uuuu/MM/dd||epoch_millis"
  8. }
  9. }
  10. }
  11. }

次に、古いインデックスから新しいインデックスにデータを再インデックスします。

以下の再インデックスAPIリクエストは、my-index-000001からmy-index-000002にデータを再インデックスします。

Python

  1. resp = client.reindex(
  2. source={
  3. "index": "my-index-000001"
  4. },
  5. dest={
  6. "index": "my-index-000002"
  7. },
  8. )
  9. print(resp)

Ruby

  1. response = client.reindex(
  2. body: {
  3. source: {
  4. index: 'my-index-000001'
  5. },
  6. dest: {
  7. index: 'my-index-000002'
  8. }
  9. }
  10. )
  11. puts response

Js

  1. const response = await client.reindex({
  2. source: {
  3. index: "my-index-000001",
  4. },
  5. dest: {
  6. index: "my-index-000002",
  7. },
  8. });
  9. console.log(response);

コンソール

  1. POST _reindex
  2. {
  3. "source": {
  4. "index": "my-index-000001"
  5. },
  6. "dest": {
  7. "index": "my-index-000002"
  8. }
  9. }

インデックスエイリアスを使用している場合は、それらを新しいインデックスを指すように更新します。

Python

  1. resp = client.indices.update_aliases(
  2. actions=[
  3. {
  4. "remove": {
  5. "index": "my-index-000001",
  6. "alias": "my-index"
  7. }
  8. },
  9. {
  10. "add": {
  11. "index": "my-index-000002",
  12. "alias": "my-index"
  13. }
  14. }
  15. ],
  16. )
  17. print(resp)

Js

  1. const response = await client.indices.updateAliases({
  2. actions: [
  3. {
  4. remove: {
  5. index: "my-index-000001",
  6. alias: "my-index",
  7. },
  8. },
  9. {
  10. add: {
  11. index: "my-index-000002",
  12. alias: "my-index",
  13. },
  14. },
  15. ],
  16. });
  17. console.log(response);

コンソール

  1. POST /_aliases
  2. {
  3. "actions" : [
  4. { "remove" : { "index" : "my-index-000001", "alias" : "my-index" } },
  5. { "add" : { "index" : "my-index-000002", "alias" : "my-index" } }
  6. ]
  7. }