ランタイムフィールドのインデックス

ランタイムフィールドは、それが実行されるコンテキストによって定義されます。たとえば、検索クエリのコンテキストや、インデックスマッピングのruntimeセクション内でランタイムフィールドを定義できます。パフォーマンスを向上させるためにランタイムフィールドをインデックスすることを決定した場合は、完全なランタイムフィールド定義(スクリプトを含む)をインデックスマッピングのコンテキストに移動するだけです。Elasticsearchは自動的にこれらのインデックスフィールドを使用してクエリを実行し、迅速な応答時間を実現します。この機能により、スクリプトを一度だけ記述し、ランタイムフィールドをサポートする任意のコンテキストに適用できます。

  1. その後、ランタイムフィールドを使用して、Elasticsearchが値を計算する必要があるフィールドの数を制限できます。インデックスフィールドとランタイムフィールドを併用することで、インデックスするデータと他のフィールドのクエリを定義する方法に柔軟性が提供されます。
  2. ランタイムフィールドをインデックスした後、含まれているスクリプトを更新することはできません。スクリプトを変更する必要がある場合は、更新されたスクリプトを持つ新しいフィールドを作成してください。
  3. たとえば、あなたの会社が古い圧力バルブを交換したいとします。接続されたセンサーは、真の読み取り値の一部しか報告できません。圧力バルブに新しいセンサーを取り付けるのではなく、報告された読み取り値に基づいて値を計算することに決めました。報告されたデータに基づいて、`````my-index-000001`````のマッピングに次のフィールドを定義します:
  4. #### Python
  5. ``````python
  6. resp = client.indices.create(
  7. index="my-index-000001",
  8. mappings={
  9. "properties": {
  10. "timestamp": {
  11. "type": "date"
  12. },
  13. "temperature": {
  14. "type": "long"
  15. },
  16. "voltage": {
  17. "type": "double"
  18. },
  19. "node": {
  20. "type": "keyword"
  21. }
  22. }
  23. },
  24. )
  25. print(resp)
  26. `

Ruby

  1. response = client.indices.create(
  2. index: 'my-index-000001',
  3. body: {
  4. mappings: {
  5. properties: {
  6. timestamp: {
  7. type: 'date'
  8. },
  9. temperature: {
  10. type: 'long'
  11. },
  12. voltage: {
  13. type: 'double'
  14. },
  15. node: {
  16. type: 'keyword'
  17. }
  18. }
  19. }
  20. }
  21. )
  22. puts response

Js

  1. const response = await client.indices.create({
  2. index: "my-index-000001",
  3. mappings: {
  4. properties: {
  5. timestamp: {
  6. type: "date",
  7. },
  8. temperature: {
  9. type: "long",
  10. },
  11. voltage: {
  12. type: "double",
  13. },
  14. node: {
  15. type: "keyword",
  16. },
  17. },
  18. },
  19. });
  20. console.log(response);

コンソール

  1. PUT my-index-000001/
  2. {
  3. "mappings": {
  4. "properties": {
  5. "timestamp": {
  6. "type": "date"
  7. },
  8. "temperature": {
  9. "type": "long"
  10. },
  11. "voltage": {
  12. "type": "double"
  13. },
  14. "node": {
  15. "type": "keyword"
  16. }
  17. }
  18. }
  19. }

その後、センサーからのサンプルデータを一括インデックスします。このデータには、各センサーのvoltageの読み取り値が含まれています:

Python

  1. resp = client.bulk(
  2. index="my-index-000001",
  3. refresh=True,
  4. operations=[
  5. {
  6. "index": {}
  7. },
  8. {
  9. "timestamp": 1516729294000,
  10. "temperature": 200,
  11. "voltage": 5.2,
  12. "node": "a"
  13. },
  14. {
  15. "index": {}
  16. },
  17. {
  18. "timestamp": 1516642894000,
  19. "temperature": 201,
  20. "voltage": 5.8,
  21. "node": "b"
  22. },
  23. {
  24. "index": {}
  25. },
  26. {
  27. "timestamp": 1516556494000,
  28. "temperature": 202,
  29. "voltage": 5.1,
  30. "node": "a"
  31. },
  32. {
  33. "index": {}
  34. },
  35. {
  36. "timestamp": 1516470094000,
  37. "temperature": 198,
  38. "voltage": 5.6,
  39. "node": "b"
  40. },
  41. {
  42. "index": {}
  43. },
  44. {
  45. "timestamp": 1516383694000,
  46. "temperature": 200,
  47. "voltage": 4.2,
  48. "node": "c"
  49. },
  50. {
  51. "index": {}
  52. },
  53. {
  54. "timestamp": 1516297294000,
  55. "temperature": 202,
  56. "voltage": 4,
  57. "node": "c"
  58. }
  59. ],
  60. )
  61. print(resp)

Ruby

  1. response = client.bulk(
  2. index: 'my-index-000001',
  3. refresh: true,
  4. body: [
  5. {
  6. index: {}
  7. },
  8. {
  9. timestamp: 1_516_729_294_000,
  10. temperature: 200,
  11. voltage: 5.2,
  12. node: 'a'
  13. },
  14. {
  15. index: {}
  16. },
  17. {
  18. timestamp: 1_516_642_894_000,
  19. temperature: 201,
  20. voltage: 5.8,
  21. node: 'b'
  22. },
  23. {
  24. index: {}
  25. },
  26. {
  27. timestamp: 1_516_556_494_000,
  28. temperature: 202,
  29. voltage: 5.1,
  30. node: 'a'
  31. },
  32. {
  33. index: {}
  34. },
  35. {
  36. timestamp: 1_516_470_094_000,
  37. temperature: 198,
  38. voltage: 5.6,
  39. node: 'b'
  40. },
  41. {
  42. index: {}
  43. },
  44. {
  45. timestamp: 1_516_383_694_000,
  46. temperature: 200,
  47. voltage: 4.2,
  48. node: 'c'
  49. },
  50. {
  51. index: {}
  52. },
  53. {
  54. timestamp: 1_516_297_294_000,
  55. temperature: 202,
  56. voltage: 4,
  57. node: 'c'
  58. }
  59. ]
  60. )
  61. puts response

Js

  1. const response = await client.bulk({
  2. index: "my-index-000001",
  3. refresh: "true",
  4. operations: [
  5. {
  6. index: {},
  7. },
  8. {
  9. timestamp: 1516729294000,
  10. temperature: 200,
  11. voltage: 5.2,
  12. node: "a",
  13. },
  14. {
  15. index: {},
  16. },
  17. {
  18. timestamp: 1516642894000,
  19. temperature: 201,
  20. voltage: 5.8,
  21. node: "b",
  22. },
  23. {
  24. index: {},
  25. },
  26. {
  27. timestamp: 1516556494000,
  28. temperature: 202,
  29. voltage: 5.1,
  30. node: "a",
  31. },
  32. {
  33. index: {},
  34. },
  35. {
  36. timestamp: 1516470094000,
  37. temperature: 198,
  38. voltage: 5.6,
  39. node: "b",
  40. },
  41. {
  42. index: {},
  43. },
  44. {
  45. timestamp: 1516383694000,
  46. temperature: 200,
  47. voltage: 4.2,
  48. node: "c",
  49. },
  50. {
  51. index: {},
  52. },
  53. {
  54. timestamp: 1516297294000,
  55. temperature: 202,
  56. voltage: 4,
  57. node: "c",
  58. },
  59. ],
  60. });
  61. console.log(response);

コンソール

  1. POST my-index-000001/_bulk?refresh=true
  2. {"index":{}}
  3. {"timestamp": 1516729294000, "temperature": 200, "voltage": 5.2, "node": "a"}
  4. {"index":{}}
  5. {"timestamp": 1516642894000, "temperature": 201, "voltage": 5.8, "node": "b"}
  6. {"index":{}}
  7. {"timestamp": 1516556494000, "temperature": 202, "voltage": 5.1, "node": "a"}
  8. {"index":{}}
  9. {"timestamp": 1516470094000, "temperature": 198, "voltage": 5.6, "node": "b"}
  10. {"index":{}}
  11. {"timestamp": 1516383694000, "temperature": 200, "voltage": 4.2, "node": "c"}
  12. {"index":{}}
  13. {"timestamp": 1516297294000, "temperature": 202, "voltage": 4.0, "node": "c"}

数人の現場エンジニアと話した後、センサーは現在の値の少なくともを報告する必要があることに気付きますが、さらに高くなる可能性があります。voltage_correctedという名前のランタイムフィールドを作成し、現在の電圧を取得して2で掛け算します:

Python

  1. resp = client.indices.put_mapping(
  2. index="my-index-000001",
  3. runtime={
  4. "voltage_corrected": {
  5. "type": "double",
  6. "script": {
  7. "source": "\n emit(doc['voltage'].value * params['multiplier'])\n ",
  8. "params": {
  9. "multiplier": 2
  10. }
  11. }
  12. }
  13. },
  14. )
  15. print(resp)

Ruby

  1. response = client.indices.put_mapping(
  2. index: 'my-index-000001',
  3. body: {
  4. runtime: {
  5. voltage_corrected: {
  6. type: 'double',
  7. script: {
  8. source: "\n emit(doc['voltage'].value * params['multiplier'])\n ",
  9. params: {
  10. multiplier: 2
  11. }
  12. }
  13. }
  14. }
  15. }
  16. )
  17. puts response

Js

  1. const response = await client.indices.putMapping({
  2. index: "my-index-000001",
  3. runtime: {
  4. voltage_corrected: {
  5. type: "double",
  6. script: {
  7. source:
  8. "\n emit(doc['voltage'].value * params['multiplier'])\n ",
  9. params: {
  10. multiplier: 2,
  11. },
  12. },
  13. },
  14. },
  15. });
  16. console.log(response);

コンソール

  1. PUT my-index-000001/_mapping
  2. {
  3. "runtime": {
  4. "voltage_corrected": {
  5. "type": "double",
  6. "script": {
  7. "source": """
  8. emit(doc['voltage'].value * params['multiplier'])
  9. """,
  10. "params": {
  11. "multiplier": 2
  12. }
  13. }
  14. }
  15. }
  16. }

計算された値は、_search APIのfieldsパラメータを使用して取得します:

Python

  1. resp = client.search(
  2. index="my-index-000001",
  3. fields=[
  4. "voltage_corrected",
  5. "node"
  6. ],
  7. size=2,
  8. )
  9. print(resp)

Ruby

  1. response = client.search(
  2. index: 'my-index-000001',
  3. body: {
  4. fields: [
  5. 'voltage_corrected',
  6. 'node'
  7. ],
  8. size: 2
  9. }
  10. )
  11. puts response

Js

  1. const response = await client.search({
  2. index: "my-index-000001",
  3. fields: ["voltage_corrected", "node"],
  4. size: 2,
  5. });
  6. console.log(response);

コンソール

  1. GET my-index-000001/_search
  2. {
  3. "fields": [
  4. "voltage_corrected",
  5. "node"
  6. ],
  7. "size": 2
  8. }

センサーデータをレビューし、いくつかのテストを実行した後、報告されたセンサーデータの乗数は4であるべきだと判断します。パフォーマンスを向上させるために、voltage_correctedランタイムフィールドを新しいmultiplierパラメータでインデックスすることに決めました。

新しいインデックスmy-index-000001に、voltage_correctedランタイムフィールドの定義を新しいインデックスのマッピングにコピーします。それはそれだけです!スクリプトがインデックス時にエラーをスローした場合に、ドキュメント全体を拒否するかどうかを決定するオプションのパラメータon_script_errorを追加できます(デフォルト)。

Python

  1. resp = client.indices.create(
  2. index="my-index-000001",
  3. mappings={
  4. "properties": {
  5. "timestamp": {
  6. "type": "date"
  7. },
  8. "temperature": {
  9. "type": "long"
  10. },
  11. "voltage": {
  12. "type": "double"
  13. },
  14. "node": {
  15. "type": "keyword"
  16. },
  17. "voltage_corrected": {
  18. "type": "double",
  19. "on_script_error": "fail",
  20. "script": {
  21. "source": "\n emit(doc['voltage'].value * params['multiplier'])\n ",
  22. "params": {
  23. "multiplier": 4
  24. }
  25. }
  26. }
  27. }
  28. },
  29. )
  30. print(resp)

Ruby

  1. response = client.indices.create(
  2. index: 'my-index-000001',
  3. body: {
  4. mappings: {
  5. properties: {
  6. timestamp: {
  7. type: 'date'
  8. },
  9. temperature: {
  10. type: 'long'
  11. },
  12. voltage: {
  13. type: 'double'
  14. },
  15. node: {
  16. type: 'keyword'
  17. },
  18. voltage_corrected: {
  19. type: 'double',
  20. on_script_error: 'fail',
  21. script: {
  22. source: "\n emit(doc['voltage'].value * params['multiplier'])\n ",
  23. params: {
  24. multiplier: 4
  25. }
  26. }
  27. }
  28. }
  29. }
  30. }
  31. )
  32. puts response

Js

  1. const response = await client.indices.create({
  2. index: "my-index-000001",
  3. mappings: {
  4. properties: {
  5. timestamp: {
  6. type: "date",
  7. },
  8. temperature: {
  9. type: "long",
  10. },
  11. voltage: {
  12. type: "double",
  13. },
  14. node: {
  15. type: "keyword",
  16. },
  17. voltage_corrected: {
  18. type: "double",
  19. on_script_error: "fail",
  20. script: {
  21. source:
  22. "\n emit(doc['voltage'].value * params['multiplier'])\n ",
  23. params: {
  24. multiplier: 4,
  25. },
  26. },
  27. },
  28. },
  29. },
  30. });
  31. console.log(response);

コンソール

  1. PUT my-index-000001/
  2. {
  3. "mappings": {
  4. "properties": {
  5. "timestamp": {
  6. "type": "date"
  7. },
  8. "temperature": {
  9. "type": "long"
  10. },
  11. "voltage": {
  12. "type": "double"
  13. },
  14. "node": {
  15. "type": "keyword"
  16. },
  17. "voltage_corrected": {
  18. "type": "double",
  19. "on_script_error": "fail",
  20. "script": {
  21. "source": """
  22. emit(doc['voltage'].value * params['multiplier'])
  23. """,
  24. "params": {
  25. "multiplier": 4
  26. }
  27. }
  28. }
  29. }
  30. }
  31. }
スクリプトがインデックス時にエラーをスローした場合、ドキュメント全体が拒否されます。値をignoreに設定すると、フィールドがドキュメントの_ignoredメタデータフィールドに登録され、インデックスが続行されます。

センサーからのサンプルデータをmy-index-000001インデックスに一括インデックスします:

Python

  1. resp = client.bulk(
  2. index="my-index-000001",
  3. refresh=True,
  4. operations=[
  5. {
  6. "index": {}
  7. },
  8. {
  9. "timestamp": 1516729294000,
  10. "temperature": 200,
  11. "voltage": 5.2,
  12. "node": "a"
  13. },
  14. {
  15. "index": {}
  16. },
  17. {
  18. "timestamp": 1516642894000,
  19. "temperature": 201,
  20. "voltage": 5.8,
  21. "node": "b"
  22. },
  23. {
  24. "index": {}
  25. },
  26. {
  27. "timestamp": 1516556494000,
  28. "temperature": 202,
  29. "voltage": 5.1,
  30. "node": "a"
  31. },
  32. {
  33. "index": {}
  34. },
  35. {
  36. "timestamp": 1516470094000,
  37. "temperature": 198,
  38. "voltage": 5.6,
  39. "node": "b"
  40. },
  41. {
  42. "index": {}
  43. },
  44. {
  45. "timestamp": 1516383694000,
  46. "temperature": 200,
  47. "voltage": 4.2,
  48. "node": "c"
  49. },
  50. {
  51. "index": {}
  52. },
  53. {
  54. "timestamp": 1516297294000,
  55. "temperature": 202,
  56. "voltage": 4,
  57. "node": "c"
  58. }
  59. ],
  60. )
  61. print(resp)

Ruby

  1. response = client.bulk(
  2. index: 'my-index-000001',
  3. refresh: true,
  4. body: [
  5. {
  6. index: {}
  7. },
  8. {
  9. timestamp: 1_516_729_294_000,
  10. temperature: 200,
  11. voltage: 5.2,
  12. node: 'a'
  13. },
  14. {
  15. index: {}
  16. },
  17. {
  18. timestamp: 1_516_642_894_000,
  19. temperature: 201,
  20. voltage: 5.8,
  21. node: 'b'
  22. },
  23. {
  24. index: {}
  25. },
  26. {
  27. timestamp: 1_516_556_494_000,
  28. temperature: 202,
  29. voltage: 5.1,
  30. node: 'a'
  31. },
  32. {
  33. index: {}
  34. },
  35. {
  36. timestamp: 1_516_470_094_000,
  37. temperature: 198,
  38. voltage: 5.6,
  39. node: 'b'
  40. },
  41. {
  42. index: {}
  43. },
  44. {
  45. timestamp: 1_516_383_694_000,
  46. temperature: 200,
  47. voltage: 4.2,
  48. node: 'c'
  49. },
  50. {
  51. index: {}
  52. },
  53. {
  54. timestamp: 1_516_297_294_000,
  55. temperature: 202,
  56. voltage: 4,
  57. node: 'c'
  58. }
  59. ]
  60. )
  61. puts response

Js

  1. const response = await client.bulk({
  2. index: "my-index-000001",
  3. refresh: "true",
  4. operations: [
  5. {
  6. index: {},
  7. },
  8. {
  9. timestamp: 1516729294000,
  10. temperature: 200,
  11. voltage: 5.2,
  12. node: "a",
  13. },
  14. {
  15. index: {},
  16. },
  17. {
  18. timestamp: 1516642894000,
  19. temperature: 201,
  20. voltage: 5.8,
  21. node: "b",
  22. },
  23. {
  24. index: {},
  25. },
  26. {
  27. timestamp: 1516556494000,
  28. temperature: 202,
  29. voltage: 5.1,
  30. node: "a",
  31. },
  32. {
  33. index: {},
  34. },
  35. {
  36. timestamp: 1516470094000,
  37. temperature: 198,
  38. voltage: 5.6,
  39. node: "b",
  40. },
  41. {
  42. index: {},
  43. },
  44. {
  45. timestamp: 1516383694000,
  46. temperature: 200,
  47. voltage: 4.2,
  48. node: "c",
  49. },
  50. {
  51. index: {},
  52. },
  53. {
  54. timestamp: 1516297294000,
  55. temperature: 202,
  56. voltage: 4,
  57. node: "c",
  58. },
  59. ],
  60. });
  61. console.log(response);

コンソール

  1. POST my-index-000001/_bulk?refresh=true
  2. { "index": {}}
  3. { "timestamp": 1516729294000, "temperature": 200, "voltage": 5.2, "node": "a"}
  4. { "index": {}}
  5. { "timestamp": 1516642894000, "temperature": 201, "voltage": 5.8, "node": "b"}
  6. { "index": {}}
  7. { "timestamp": 1516556494000, "temperature": 202, "voltage": 5.1, "node": "a"}
  8. { "index": {}}
  9. { "timestamp": 1516470094000, "temperature": 198, "voltage": 5.6, "node": "b"}
  10. { "index": {}}
  11. { "timestamp": 1516383694000, "temperature": 200, "voltage": 4.2, "node": "c"}
  12. { "index": {}}
  13. { "timestamp": 1516297294000, "temperature": 202, "voltage": 4.0, "node": "c"}

検索クエリで計算された値を取得できるようになり、正確な値に基づいてドキュメントを見つけることができます。次の範囲クエリは、計算されたvoltage_corrected16以上、20以下のすべてのドキュメントを返します。再度、fieldsパラメータを_search APIで使用して、必要なフィールドを取得します:

Python

  1. resp = client.search(
  2. index="my-index-000001",
  3. query={
  4. "range": {
  5. "voltage_corrected": {
  6. "gte": 16,
  7. "lte": 20,
  8. "boost": 1
  9. }
  10. }
  11. },
  12. fields=[
  13. "voltage_corrected",
  14. "node"
  15. ],
  16. )
  17. print(resp)

Js

  1. const response = await client.search({
  2. index: "my-index-000001",
  3. query: {
  4. range: {
  5. voltage_corrected: {
  6. gte: 16,
  7. lte: 20,
  8. boost: 1,
  9. },
  10. },
  11. },
  12. fields: ["voltage_corrected", "node"],
  13. });
  14. console.log(response);

コンソール

  1. POST my-index-000001/_search
  2. {
  3. "query": {
  4. "range": {
  5. "voltage_corrected": {
  6. "gte": 16,
  7. "lte": 20,
  8. "boost": 1.0
  9. }
  10. }
  11. },
  12. "fields": ["voltage_corrected", "node"]
  13. }

応答には、計算された値に基づいて範囲クエリに一致するドキュメントのvoltage_correctedフィールドが含まれます:

コンソール-結果

  1. {
  2. "hits" : {
  3. "total" : {
  4. "value" : 2,
  5. "relation" : "eq"
  6. },
  7. "max_score" : 1.0,
  8. "hits" : [
  9. {
  10. "_index" : "my-index-000001",
  11. "_id" : "yoSLrHgBdg9xpPrUZz_P",
  12. "_score" : 1.0,
  13. "_source" : {
  14. "timestamp" : 1516383694000,
  15. "temperature" : 200,
  16. "voltage" : 4.2,
  17. "node" : "c"
  18. },
  19. "fields" : {
  20. "voltage_corrected" : [
  21. 16.8
  22. ],
  23. "node" : [
  24. "c"
  25. ]
  26. }
  27. },
  28. {
  29. "_index" : "my-index-000001",
  30. "_id" : "y4SLrHgBdg9xpPrUZz_P",
  31. "_score" : 1.0,
  32. "_source" : {
  33. "timestamp" : 1516297294000,
  34. "temperature" : 202,
  35. "voltage" : 4.0,
  36. "node" : "c"
  37. },
  38. "fields" : {
  39. "voltage_corrected" : [
  40. 16.0
  41. ],
  42. "node" : [
  43. "c"
  44. ]
  45. }
  46. }
  47. ]
  48. }
  49. }