ドキュメントフィールドと特別な変数へのアクセス

スクリプトが使用される場所に応じて、特定の特別な変数やドキュメントフィールドにアクセスできます。

ドキュメントフィールドと特別な変数へのアクセス

スクリプトが使用される場所に応じて、特定の特別な変数やドキュメントフィールドにアクセスできます。

検索および集約スクリプト

検索ヒットごとに一度実行される スクリプトフィールド を除いて、検索および集約で使用されるスクリプトは、クエリまたは集約に一致する可能性のある各ドキュメントごとに一度実行されます。ドキュメントの数によっては、これは数百万または数十億回の実行を意味する可能性があります: これらのスクリプトは高速である必要があります!

フィールド値は、doc-values_source フィールド、または ストレージフィールド を使用してスクリプトからアクセスできます。これらは以下で説明します。

スクリプト内でのドキュメントのスコアへのアクセス

function_score クエリスクリプトベースのソート、または 集約 で使用されるスクリプトは、ドキュメントの現在の関連性スコアを表す _score 変数にアクセスできます。

以下は、function_score クエリ でスクリプトを使用して各ドキュメントの関連性 _score を変更する例です:

Python

  1. resp = client.index(
  2. index="my-index-000001",
  3. id="1",
  4. refresh=True,
  5. document={
  6. "text": "quick brown fox",
  7. "popularity": 1
  8. },
  9. )
  10. print(resp)
  11. resp1 = client.index(
  12. index="my-index-000001",
  13. id="2",
  14. refresh=True,
  15. document={
  16. "text": "quick fox",
  17. "popularity": 5
  18. },
  19. )
  20. print(resp1)
  21. resp2 = client.search(
  22. index="my-index-000001",
  23. query={
  24. "function_score": {
  25. "query": {
  26. "match": {
  27. "text": "quick brown fox"
  28. }
  29. },
  30. "script_score": {
  31. "script": {
  32. "lang": "expression",
  33. "source": "_score * doc['popularity']"
  34. }
  35. }
  36. }
  37. },
  38. )
  39. print(resp2)

Ruby

  1. response = client.index(
  2. index: 'my-index-000001',
  3. id: 1,
  4. refresh: true,
  5. body: {
  6. text: 'quick brown fox',
  7. popularity: 1
  8. }
  9. )
  10. puts response
  11. response = client.index(
  12. index: 'my-index-000001',
  13. id: 2,
  14. refresh: true,
  15. body: {
  16. text: 'quick fox',
  17. popularity: 5
  18. }
  19. )
  20. puts response
  21. response = client.search(
  22. index: 'my-index-000001',
  23. body: {
  24. query: {
  25. function_score: {
  26. query: {
  27. match: {
  28. text: 'quick brown fox'
  29. }
  30. },
  31. script_score: {
  32. script: {
  33. lang: 'expression',
  34. source: "_score * doc['popularity']"
  35. }
  36. }
  37. }
  38. }
  39. }
  40. )
  41. puts response

Js

  1. const response = await client.index({
  2. index: "my-index-000001",
  3. id: 1,
  4. refresh: "true",
  5. document: {
  6. text: "quick brown fox",
  7. popularity: 1,
  8. },
  9. });
  10. console.log(response);
  11. const response1 = await client.index({
  12. index: "my-index-000001",
  13. id: 2,
  14. refresh: "true",
  15. document: {
  16. text: "quick fox",
  17. popularity: 5,
  18. },
  19. });
  20. console.log(response1);
  21. const response2 = await client.search({
  22. index: "my-index-000001",
  23. query: {
  24. function_score: {
  25. query: {
  26. match: {
  27. text: "quick brown fox",
  28. },
  29. },
  30. script_score: {
  31. script: {
  32. lang: "expression",
  33. source: "_score * doc['popularity']",
  34. },
  35. },
  36. },
  37. },
  38. });
  39. console.log(response2);

コンソール

  1. PUT my-index-000001/_doc/1?refresh
  2. {
  3. "text": "quick brown fox",
  4. "popularity": 1
  5. }
  6. PUT my-index-000001/_doc/2?refresh
  7. {
  8. "text": "quick fox",
  9. "popularity": 5
  10. }
  11. GET my-index-000001/_search
  12. {
  13. "query": {
  14. "function_score": {
  15. "query": {
  16. "match": {
  17. "text": "quick brown fox"
  18. }
  19. },
  20. "script_score": {
  21. "script": {
  22. "lang": "expression",
  23. "source": "_score * doc['popularity']"
  24. }
  25. }
  26. }
  27. }
  28. }

ドキュメント値

スクリプトからフィールド値にアクセスする最も高速で効率的な方法は、doc['field_name'] 構文を使用することです。これは、doc values からフィールド値を取得します。ドキュメント値は、すべてのフィールドに対してデフォルトで有効になっている列指向のフィールド値ストアで、分析された text フィールド を除きます。

Python

  1. resp = client.index(
  2. index="my-index-000001",
  3. id="1",
  4. refresh=True,
  5. document={
  6. "cost_price": 100
  7. },
  8. )
  9. print(resp)
  10. resp1 = client.search(
  11. index="my-index-000001",
  12. script_fields={
  13. "sales_price": {
  14. "script": {
  15. "lang": "expression",
  16. "source": "doc['cost_price'] * markup",
  17. "params": {
  18. "markup": 0.2
  19. }
  20. }
  21. }
  22. },
  23. )
  24. print(resp1)

Ruby

  1. response = client.index(
  2. index: 'my-index-000001',
  3. id: 1,
  4. refresh: true,
  5. body: {
  6. cost_price: 100
  7. }
  8. )
  9. puts response
  10. response = client.search(
  11. index: 'my-index-000001',
  12. body: {
  13. script_fields: {
  14. sales_price: {
  15. script: {
  16. lang: 'expression',
  17. source: "doc['cost_price'] * markup",
  18. params: {
  19. markup: 0.2
  20. }
  21. }
  22. }
  23. }
  24. }
  25. )
  26. puts response

Js

  1. const response = await client.index({
  2. index: "my-index-000001",
  3. id: 1,
  4. refresh: "true",
  5. document: {
  6. cost_price: 100,
  7. },
  8. });
  9. console.log(response);
  10. const response1 = await client.search({
  11. index: "my-index-000001",
  12. script_fields: {
  13. sales_price: {
  14. script: {
  15. lang: "expression",
  16. source: "doc['cost_price'] * markup",
  17. params: {
  18. markup: 0.2,
  19. },
  20. },
  21. },
  22. },
  23. });
  24. console.log(response1);

コンソール

  1. PUT my-index-000001/_doc/1?refresh
  2. {
  3. "cost_price": 100
  4. }
  5. GET my-index-000001/_search
  6. {
  7. "script_fields": {
  8. "sales_price": {
  9. "script": {
  10. "lang": "expression",
  11. "source": "doc['cost_price'] * markup",
  12. "params": {
  13. "markup": 0.2
  14. }
  15. }
  16. }
  17. }
  18. }

ドキュメント値は、数値、日付、地理的ポイント、用語などの「単純な」フィールド値や、フィールドが多値の場合はこれらの値の配列のみを返すことができます。JSONオブジェクトを返すことはできません。

欠落しているフィールド

doc['field'] は、field がマッピングから欠落している場合にエラーをスローします。painless では、doc.containsKey('field') を使用して doc マップへのアクセスを保護するために最初にチェックを行うことができます。残念ながら、expression スクリプト内でマッピングにフィールドの存在を確認する方法はありません。

ドキュメント値とテキストフィールド

doc['field'] 構文は、text フィールド に対しても使用できますが、fielddata が有効になっている場合に限ります。ただし、注意: text フィールドでフィールドデータを有効にすると、すべての用語がJVMヒープにロードされる必要があり、メモリとCPUの両方の観点から非常に高価になる可能性があります。スクリプトから text フィールドにアクセスすることはほとんど意味がありません。

ドキュメント _source

ドキュメント _source は、_source.field_name 構文を使用してアクセスできます。_source はマップのマップとしてロードされるため、オブジェクトフィールド内のプロパティには、例えば _source.name.first のようにアクセスできます。

ドキュメント値を _source より優先する

_source フィールドへのアクセスは、ドキュメント値を使用するよりもはるかに遅くなります。_source フィールドは、結果ごとに複数のフィールドを返すように最適化されているのに対し、ドキュメント値は多くのドキュメント内の特定のフィールドの値にアクセスするように最適化されています。

検索結果の上位10件から スクリプトフィールド を生成する際には _source を使用するのが理にかなっていますが、他の検索および集約のユースケースでは、常にドキュメント値を使用することを優先してください。

例えば:

Python

  1. resp = client.indices.create(
  2. index="my-index-000001",
  3. mappings={
  4. "properties": {
  5. "first_name": {
  6. "type": "text"
  7. },
  8. "last_name": {
  9. "type": "text"
  10. }
  11. }
  12. },
  13. )
  14. print(resp)
  15. resp1 = client.index(
  16. index="my-index-000001",
  17. id="1",
  18. refresh=True,
  19. document={
  20. "first_name": "Barry",
  21. "last_name": "White"
  22. },
  23. )
  24. print(resp1)
  25. resp2 = client.search(
  26. index="my-index-000001",
  27. script_fields={
  28. "full_name": {
  29. "script": {
  30. "lang": "painless",
  31. "source": "params._source.first_name + ' ' + params._source.last_name"
  32. }
  33. }
  34. },
  35. )
  36. print(resp2)

Ruby

  1. response = client.indices.create(
  2. index: 'my-index-000001',
  3. body: {
  4. mappings: {
  5. properties: {
  6. first_name: {
  7. type: 'text'
  8. },
  9. last_name: {
  10. type: 'text'
  11. }
  12. }
  13. }
  14. }
  15. )
  16. puts response
  17. response = client.index(
  18. index: 'my-index-000001',
  19. id: 1,
  20. refresh: true,
  21. body: {
  22. first_name: 'Barry',
  23. last_name: 'White'
  24. }
  25. )
  26. puts response
  27. response = client.search(
  28. index: 'my-index-000001',
  29. body: {
  30. script_fields: {
  31. full_name: {
  32. script: {
  33. lang: 'painless',
  34. source: "params._source.first_name + ' ' + params._source.last_name"
  35. }
  36. }
  37. }
  38. }
  39. )
  40. puts response

Js

  1. const response = await client.indices.create({
  2. index: "my-index-000001",
  3. mappings: {
  4. properties: {
  5. first_name: {
  6. type: "text",
  7. },
  8. last_name: {
  9. type: "text",
  10. },
  11. },
  12. },
  13. });
  14. console.log(response);
  15. const response1 = await client.index({
  16. index: "my-index-000001",
  17. id: 1,
  18. refresh: "true",
  19. document: {
  20. first_name: "Barry",
  21. last_name: "White",
  22. },
  23. });
  24. console.log(response1);
  25. const response2 = await client.search({
  26. index: "my-index-000001",
  27. script_fields: {
  28. full_name: {
  29. script: {
  30. lang: "painless",
  31. source: "params._source.first_name + ' ' + params._source.last_name",
  32. },
  33. },
  34. },
  35. });
  36. console.log(response2);

コンソール

  1. PUT my-index-000001
  2. {
  3. "mappings": {
  4. "properties": {
  5. "first_name": {
  6. "type": "text"
  7. },
  8. "last_name": {
  9. "type": "text"
  10. }
  11. }
  12. }
  13. }
  14. PUT my-index-000001/_doc/1?refresh
  15. {
  16. "first_name": "Barry",
  17. "last_name": "White"
  18. }
  19. GET my-index-000001/_search
  20. {
  21. "script_fields": {
  22. "full_name": {
  23. "script": {
  24. "lang": "painless",
  25. "source": "params._source.first_name + ' ' + params._source.last_name"
  26. }
  27. }
  28. }
  29. }

ストレージフィールド

ストレージフィールド—マッピングで明示的に "store": true としてマークされたフィールド—は、_fields['field_name'].value または _fields['field_name'] 構文を使用してアクセスできます:

Python

  1. resp = client.indices.create(
  2. index="my-index-000001",
  3. mappings={
  4. "properties": {
  5. "full_name": {
  6. "type": "text",
  7. "store": True
  8. },
  9. "title": {
  10. "type": "text",
  11. "store": True
  12. }
  13. }
  14. },
  15. )
  16. print(resp)
  17. resp1 = client.index(
  18. index="my-index-000001",
  19. id="1",
  20. refresh=True,
  21. document={
  22. "full_name": "Alice Ball",
  23. "title": "Professor"
  24. },
  25. )
  26. print(resp1)
  27. resp2 = client.search(
  28. index="my-index-000001",
  29. script_fields={
  30. "name_with_title": {
  31. "script": {
  32. "lang": "painless",
  33. "source": "params._fields['title'].value + ' ' + params._fields['full_name'].value"
  34. }
  35. }
  36. },
  37. )
  38. print(resp2)

Ruby

  1. response = client.indices.create(
  2. index: 'my-index-000001',
  3. body: {
  4. mappings: {
  5. properties: {
  6. full_name: {
  7. type: 'text',
  8. store: true
  9. },
  10. title: {
  11. type: 'text',
  12. store: true
  13. }
  14. }
  15. }
  16. }
  17. )
  18. puts response
  19. response = client.index(
  20. index: 'my-index-000001',
  21. id: 1,
  22. refresh: true,
  23. body: {
  24. full_name: 'Alice Ball',
  25. title: 'Professor'
  26. }
  27. )
  28. puts response
  29. response = client.search(
  30. index: 'my-index-000001',
  31. body: {
  32. script_fields: {
  33. name_with_title: {
  34. script: {
  35. lang: 'painless',
  36. source: "params._fields['title'].value + ' ' + params._fields['full_name'].value"
  37. }
  38. }
  39. }
  40. }
  41. )
  42. puts response

Js

  1. const response = await client.indices.create({
  2. index: "my-index-000001",
  3. mappings: {
  4. properties: {
  5. full_name: {
  6. type: "text",
  7. store: true,
  8. },
  9. title: {
  10. type: "text",
  11. store: true,
  12. },
  13. },
  14. },
  15. });
  16. console.log(response);
  17. const response1 = await client.index({
  18. index: "my-index-000001",
  19. id: 1,
  20. refresh: "true",
  21. document: {
  22. full_name: "Alice Ball",
  23. title: "Professor",
  24. },
  25. });
  26. console.log(response1);
  27. const response2 = await client.search({
  28. index: "my-index-000001",
  29. script_fields: {
  30. name_with_title: {
  31. script: {
  32. lang: "painless",
  33. source:
  34. "params._fields['title'].value + ' ' + params._fields['full_name'].value",
  35. },
  36. },
  37. },
  38. });
  39. console.log(response2);

コンソール

  1. PUT my-index-000001
  2. {
  3. "mappings": {
  4. "properties": {
  5. "full_name": {
  6. "type": "text",
  7. "store": true
  8. },
  9. "title": {
  10. "type": "text",
  11. "store": true
  12. }
  13. }
  14. }
  15. }
  16. PUT my-index-000001/_doc/1?refresh
  17. {
  18. "full_name": "Alice Ball",
  19. "title": "Professor"
  20. }
  21. GET my-index-000001/_search
  22. {
  23. "script_fields": {
  24. "name_with_title": {
  25. "script": {
  26. "lang": "painless",
  27. "source": "params._fields['title'].value + ' ' + params._fields['full_name'].value"
  28. }
  29. }
  30. }
  31. }

ストレージと _source

_source フィールドは特別なストレージフィールドに過ぎないため、パフォーマンスは他のストレージフィールドと同様です。_source は、インデックスされた元のドキュメント本文へのアクセスを提供します(null 値を空のフィールド、単一値の配列、プレーンスカラーなどから区別する能力を含む)。

_source フィールドの代わりにストレージフィールドを使用することが本当に意味を持つのは、_source が非常に大きく、全体の _source にアクセスするよりもいくつかの小さなストレージフィールドにアクセスする方がコストが低い場合だけです。