ランタイムフィールドのマッピング

ランタイムフィールドは、マッピング定義の下に runtime セクションを追加し、Painless スクリプトを定義することでマッピングされます。このスクリプトは、元の _sourceparams._source 経由で含むドキュメントの全コンテキストにアクセスできます。また、マッピングされたフィールドとその値にもアクセスできます。クエリ時に、スクリプトが実行され、クエリに必要な各スクリプトフィールドの値が生成されます。

ランタイムフィールド値の出力

ランタイムフィールドで使用するためのPainlessスクリプトを定義する際には、計算された値を出力するためにemit メソッドを含める必要があります。

例えば、以下のリクエストのスクリプトは、@timestamp フィールドから曜日を計算します。このフィールドは date タイプとして定義されています。スクリプトは timestamp の値に基づいて曜日を計算し、emit を使用して計算された値を返します。

Python

  1. resp = client.indices.create(
  2. index="my-index-000001",
  3. mappings={
  4. "runtime": {
  5. "day_of_week": {
  6. "type": "keyword",
  7. "script": {
  8. "source": "emit(doc['@timestamp'].value.dayOfWeekEnum.getDisplayName(TextStyle.FULL, Locale.ENGLISH))"
  9. }
  10. }
  11. },
  12. "properties": {
  13. "@timestamp": {
  14. "type": "date"
  15. }
  16. }
  17. },
  18. )
  19. print(resp)

Js

  1. const response = await client.indices.create({
  2. index: "my-index-000001",
  3. mappings: {
  4. runtime: {
  5. day_of_week: {
  6. type: "keyword",
  7. script: {
  8. source:
  9. "emit(doc['@timestamp'].value.dayOfWeekEnum.getDisplayName(TextStyle.FULL, Locale.ENGLISH))",
  10. },
  11. },
  12. },
  13. properties: {
  14. "@timestamp": {
  15. type: "date",
  16. },
  17. },
  18. },
  19. });
  20. console.log(response);

コンソール

  1. PUT my-index-000001/
  2. {
  3. "mappings": {
  4. "runtime": {
  5. "day_of_week": {
  6. "type": "keyword",
  7. "script": {
  8. "source": "emit(doc['@timestamp'].value.dayOfWeekEnum.getDisplayName(TextStyle.FULL, Locale.ENGLISH))"
  9. }
  10. }
  11. },
  12. "properties": {
  13. "@timestamp": {"type": "date"}
  14. }
  15. }
  16. }

runtime セクションは、次のデータ型のいずれかであることができます:

  • boolean
  • composite
  • date
  • double
  • geo_point
  • ip
  • keyword
  • long
  • lookup

typedate のランタイムフィールドは、format パラメータを date フィールドタイプと同様に受け入れることができます。

typelookup のランタイムフィールドは、関連インデックスからフィールドを取得することを許可します。詳細は retrieve fields from related indices を参照してください。

dynamic の動的フィールドマッピングが有効になっている場合、runtime に設定されたパラメータにより、新しいフィールドがランタイムフィールドとしてインデックスマッピングに自動的に追加されます:

Python

  1. resp = client.indices.create(
  2. index="my-index-000001",
  3. mappings={
  4. "dynamic": "runtime",
  5. "properties": {
  6. "@timestamp": {
  7. "type": "date"
  8. }
  9. }
  10. },
  11. )
  12. print(resp)

Ruby

  1. response = client.indices.create(
  2. index: 'my-index-000001',
  3. body: {
  4. mappings: {
  5. dynamic: 'runtime',
  6. properties: {
  7. "@timestamp": {
  8. type: 'date'
  9. }
  10. }
  11. }
  12. }
  13. )
  14. puts response

Js

  1. const response = await client.indices.create({
  2. index: "my-index-000001",
  3. mappings: {
  4. dynamic: "runtime",
  5. properties: {
  6. "@timestamp": {
  7. type: "date",
  8. },
  9. },
  10. },
  11. });
  12. console.log(response);

コンソール

  1. PUT my-index-000001
  2. {
  3. "mappings": {
  4. "dynamic": "runtime",
  5. "properties": {
  6. "@timestamp": {
  7. "type": "date"
  8. }
  9. }
  10. }
  11. }

スクリプトなしでのランタイムフィールドの定義

ランタイムフィールドには通常、データを何らかの方法で操作するPainlessスクリプトが含まれます。しかし、スクリプトなしでランタイムフィールドを定義する場合もあります。例えば、_source から単一のフィールドを変更せずに取得したい場合、スクリプトは必要ありません。スクリプトなしでランタイムフィールドを作成することができます。例えば、day_of_week のように:

Python

  1. resp = client.indices.create(
  2. index="my-index-000001",
  3. mappings={
  4. "runtime": {
  5. "day_of_week": {
  6. "type": "keyword"
  7. }
  8. }
  9. },
  10. )
  11. print(resp)

Ruby

  1. response = client.indices.create(
  2. index: 'my-index-000001',
  3. body: {
  4. mappings: {
  5. runtime: {
  6. day_of_week: {
  7. type: 'keyword'
  8. }
  9. }
  10. }
  11. }
  12. )
  13. puts response

Js

  1. const response = await client.indices.create({
  2. index: "my-index-000001",
  3. mappings: {
  4. runtime: {
  5. day_of_week: {
  6. type: "keyword",
  7. },
  8. },
  9. },
  10. });
  11. console.log(response);

コンソール

  1. PUT my-index-000001/
  2. {
  3. "mappings": {
  4. "runtime": {
  5. "day_of_week": {
  6. "type": "keyword"
  7. }
  8. }
  9. }
  10. }

スクリプトが提供されていない場合、Elasticsearch はクエリ時に _source で同じ名前のフィールドを暗黙的に探し、存在する場合は値を返します。同じ名前のフィールドが存在しない場合、そのランタイムフィールドの値は応答に含まれません。

ほとんどの場合、可能な限り doc_values を通じてフィールド値を取得してください。ランタイムフィールドを使用して doc_values にアクセスする方が、_source から値を取得するよりも速いです。これは、Lucene からデータが読み込まれる方法によるものです。

ただし、_source からフィールドを取得する必要がある場合もあります。例えば、text フィールドはデフォルトで doc_values を利用できないため、_source から値を取得する必要があります。他のケースでは、特定のフィールドで doc_values を無効にすることを選択するかもしれません。

取得したい値のフィールドを params._source でプレフィックスすることもできます(params._source.day_of_week など)。簡潔さのために、スクリプトなしでマッピング定義にランタイムフィールドを定義することが推奨されます。

ランタイムフィールドのスクリプトエラーを無視する

スクリプトは、ドキュメント内の欠落または無効な値にアクセスしたり、無効な操作を実行したりする際に、ランタイムエラーをスローすることがあります。on_script_error パラメータは、これが発生したときのエラー動作を制御するために使用できます。このパラメータを continue に設定すると、このランタイムフィールドのすべてのエラーを静かに無視する効果があります。デフォルトの fail 値は、シャードの失敗を引き起こし、検索応答に報告されます。

ランタイムフィールドの更新と削除

ランタイムフィールドはいつでも更新または削除できます。既存のランタイムフィールドを置き換えるには、同じ名前の新しいランタイムフィールドをマッピングに追加します。マッピングからランタイムフィールドを削除するには、ランタイムフィールドの値を null に設定します:

Python

  1. resp = client.indices.put_mapping(
  2. index="my-index-000001",
  3. runtime={
  4. "day_of_week": None
  5. },
  6. )
  7. print(resp)

Ruby

  1. response = client.indices.put_mapping(
  2. index: 'my-index-000001',
  3. body: {
  4. runtime: {
  5. day_of_week: nil
  6. }
  7. }
  8. )
  9. puts response

Js

  1. const response = await client.indices.putMapping({
  2. index: "my-index-000001",
  3. runtime: {
  4. day_of_week: null,
  5. },
  6. });
  7. console.log(response);

コンソール

  1. PUT my-index-000001/_mapping
  2. {
  3. "runtime": {
  4. "day_of_week": null
  5. }
  6. }

下流への影響

依存クエリが実行中にランタイムフィールドを更新または削除すると、一貫性のない結果が返される可能性があります。各シャードは、マッピングの変更が有効になるタイミングに応じて、異なるバージョンのスクリプトにアクセスできる場合があります。

ランタイムフィールドに依存する既存のクエリやKibanaの視覚化は、フィールドを削除または更新すると失敗する可能性があります。例えば、ip タイプのランタイムフィールドを使用する棒グラフの視覚化は、タイプが boolean に変更された場合や、ランタイムフィールドが削除された場合に失敗します。