スクリプトメトリック集約

スクリプトを使用してメトリック出力を提供するメトリック集約です。

スクリプトを使用すると、検索速度が遅くなる可能性があります。詳細は スクリプト、キャッシュ、および検索速度 を参照してください。

例:

Python

  1. resp = client.search(
  2. index="ledger",
  3. size="0",
  4. query={
  5. "match_all": {}
  6. },
  7. aggs={
  8. "profit": {
  9. "scripted_metric": {
  10. "init_script": "state.transactions = []",
  11. "map_script": "state.transactions.add(doc.type.value == 'sale' ? doc.amount.value : -1 * doc.amount.value)",
  12. "combine_script": "double profit = 0; for (t in state.transactions) { profit += t } return profit",
  13. "reduce_script": "double profit = 0; for (a in states) { profit += a } return profit"
  14. }
  15. }
  16. },
  17. )
  18. print(resp)

Ruby

  1. response = client.search(
  2. index: 'ledger',
  3. size: 0,
  4. body: {
  5. query: {
  6. match_all: {}
  7. },
  8. aggregations: {
  9. profit: {
  10. scripted_metric: {
  11. init_script: 'state.transactions = []',
  12. map_script: "state.transactions.add(doc.type.value == 'sale' ? doc.amount.value : -1 * doc.amount.value)",
  13. combine_script: 'double profit = 0; for (t in state.transactions) { profit += t } return profit',
  14. reduce_script: 'double profit = 0; for (a in states) { profit += a } return profit'
  15. }
  16. }
  17. }
  18. }
  19. )
  20. puts response

Js

  1. const response = await client.search({
  2. index: "ledger",
  3. size: 0,
  4. query: {
  5. match_all: {},
  6. },
  7. aggs: {
  8. profit: {
  9. scripted_metric: {
  10. init_script: "state.transactions = []",
  11. map_script:
  12. "state.transactions.add(doc.type.value == 'sale' ? doc.amount.value : -1 * doc.amount.value)",
  13. combine_script:
  14. "double profit = 0; for (t in state.transactions) { profit += t } return profit",
  15. reduce_script:
  16. "double profit = 0; for (a in states) { profit += a } return profit",
  17. },
  18. },
  19. },
  20. });
  21. console.log(response);

コンソール

  1. POST ledger/_search?size=0
  2. {
  3. "query": {
  4. "match_all": {}
  5. },
  6. "aggs": {
  7. "profit": {
  8. "scripted_metric": {
  9. "init_script": "state.transactions = []",
  10. "map_script": "state.transactions.add(doc.type.value == 'sale' ? doc.amount.value : -1 * doc.amount.value)",
  11. "combine_script": "double profit = 0; for (t in state.transactions) { profit += t } return profit",
  12. "reduce_script": "double profit = 0; for (a in states) { profit += a } return profit"
  13. }
  14. }
  15. }
  16. }
init_script はオプションのパラメータであり、他のすべてのスクリプトは必須です。

上記の集約は、スクリプト集約を使用して販売とコストトランザクションから総利益を計算する方法を示しています。

上記の集約に対する応答:

コンソール-結果

  1. {
  2. "took": 218,
  3. ...
  4. "aggregations": {
  5. "profit": {
  6. "value": 240.0
  7. }
  8. }
  9. }

上記の例は、次のように保存されたスクリプトを使用して指定することもできます:

Python

  1. resp = client.search(
  2. index="ledger",
  3. size="0",
  4. aggs={
  5. "profit": {
  6. "scripted_metric": {
  7. "init_script": {
  8. "id": "my_init_script"
  9. },
  10. "map_script": {
  11. "id": "my_map_script"
  12. },
  13. "combine_script": {
  14. "id": "my_combine_script"
  15. },
  16. "params": {
  17. "field": "amount"
  18. },
  19. "reduce_script": {
  20. "id": "my_reduce_script"
  21. }
  22. }
  23. }
  24. },
  25. )
  26. print(resp)

Ruby

  1. response = client.search(
  2. index: 'ledger',
  3. size: 0,
  4. body: {
  5. aggregations: {
  6. profit: {
  7. scripted_metric: {
  8. init_script: {
  9. id: 'my_init_script'
  10. },
  11. map_script: {
  12. id: 'my_map_script'
  13. },
  14. combine_script: {
  15. id: 'my_combine_script'
  16. },
  17. params: {
  18. field: 'amount'
  19. },
  20. reduce_script: {
  21. id: 'my_reduce_script'
  22. }
  23. }
  24. }
  25. }
  26. }
  27. )
  28. puts response

Js

  1. const response = await client.search({
  2. index: "ledger",
  3. size: 0,
  4. aggs: {
  5. profit: {
  6. scripted_metric: {
  7. init_script: {
  8. id: "my_init_script",
  9. },
  10. map_script: {
  11. id: "my_map_script",
  12. },
  13. combine_script: {
  14. id: "my_combine_script",
  15. },
  16. params: {
  17. field: "amount",
  18. },
  19. reduce_script: {
  20. id: "my_reduce_script",
  21. },
  22. },
  23. },
  24. },
  25. });
  26. console.log(response);

コンソール

  1. POST ledger/_search?size=0
  2. {
  3. "aggs": {
  4. "profit": {
  5. "scripted_metric": {
  6. "init_script": {
  7. "id": "my_init_script"
  8. },
  9. "map_script": {
  10. "id": "my_map_script"
  11. },
  12. "combine_script": {
  13. "id": "my_combine_script"
  14. },
  15. "params": {
  16. "field": "amount"
  17. },
  18. "reduce_script": {
  19. "id": "my_reduce_script"
  20. }
  21. }
  22. }
  23. }
  24. }
initmap、および combine スクリプトのスクリプトパラメータは、グローバル params オブジェクト内で指定する必要があります。これにより、スクリプト間で共有できます。

スクリプトの指定に関する詳細は、スクリプトドキュメントを参照してください。

許可される戻り値の型

単一のスクリプト内で有効なスクリプトオブジェクトを使用できますが、スクリプトは state オブジェクトに次の型のみを返すか保存する必要があります:

  • プリミティブ型
  • 文字列
  • マップ(ここにリストされている型のキーと値のみを含む)
  • 配列(ここにリストされている型の要素のみを含む)

スクリプトのスコープ

スクリプトメトリック集約は、実行の4つの段階でスクリプトを使用します:

  • init_script
  • ドキュメントの収集前に実行されます。集約が初期状態を設定できるようにします。
    上記の例では、init_scriptstate オブジェクト内に配列 transactions を作成します。
  • map_script
  • 収集された各ドキュメントごとに1回実行されます。これは必須のスクリプトです。
    上記の例では、map_script がタイプフィールドの値をチェックします。値が販売の場合、金額フィールドの値がトランザクション配列に追加されます。タイプフィールドの値が販売でない場合、金額フィールドの否定値がトランザクションに追加されます。
  • combine_script
  • ドキュメントの収集が完了した後、各シャードで1回実行されます。これは必須のスクリプトです。集約が各シャードから返された状態を統合できるようにします。
    上記の例では、combine_script がすべての保存されたトランザクションを反復処理し、profit 変数内の値を合計し、最終的に profit を返します。
  • reduce_script
  • すべてのシャードが結果を返した後、コーディネーティングノードで1回実行されます。これは必須のスクリプトです。スクリプトには、各シャードの combine_script の結果の配列である states 変数へのアクセスが提供されます。
    上記の例では、reduce_script が各シャードから返された profit を反復処理し、値を合計して最終的な合計利益を返します。これは集約の応答として返されます。

実例

次のドキュメントを2つのシャードを持つインデックスにインデックスする状況を想像してください:

Python

  1. resp = client.bulk(
  2. index="transactions",
  3. refresh=True,
  4. operations=[
  5. {
  6. "index": {
  7. "_id": 1
  8. }
  9. },
  10. {
  11. "type": "sale",
  12. "amount": 80
  13. },
  14. {
  15. "index": {
  16. "_id": 2
  17. }
  18. },
  19. {
  20. "type": "cost",
  21. "amount": 10
  22. },
  23. {
  24. "index": {
  25. "_id": 3
  26. }
  27. },
  28. {
  29. "type": "cost",
  30. "amount": 30
  31. },
  32. {
  33. "index": {
  34. "_id": 4
  35. }
  36. },
  37. {
  38. "type": "sale",
  39. "amount": 130
  40. }
  41. ],
  42. )
  43. print(resp)

Ruby

  1. response = client.bulk(
  2. index: 'transactions',
  3. refresh: true,
  4. body: [
  5. {
  6. index: {
  7. _id: 1
  8. }
  9. },
  10. {
  11. type: 'sale',
  12. amount: 80
  13. },
  14. {
  15. index: {
  16. _id: 2
  17. }
  18. },
  19. {
  20. type: 'cost',
  21. amount: 10
  22. },
  23. {
  24. index: {
  25. _id: 3
  26. }
  27. },
  28. {
  29. type: 'cost',
  30. amount: 30
  31. },
  32. {
  33. index: {
  34. _id: 4
  35. }
  36. },
  37. {
  38. type: 'sale',
  39. amount: 130
  40. }
  41. ]
  42. )
  43. puts response

Js

  1. const response = await client.bulk({
  2. index: "transactions",
  3. refresh: "true",
  4. operations: [
  5. {
  6. index: {
  7. _id: 1,
  8. },
  9. },
  10. {
  11. type: "sale",
  12. amount: 80,
  13. },
  14. {
  15. index: {
  16. _id: 2,
  17. },
  18. },
  19. {
  20. type: "cost",
  21. amount: 10,
  22. },
  23. {
  24. index: {
  25. _id: 3,
  26. },
  27. },
  28. {
  29. type: "cost",
  30. amount: 30,
  31. },
  32. {
  33. index: {
  34. _id: 4,
  35. },
  36. },
  37. {
  38. type: "sale",
  39. amount: 130,
  40. },
  41. ],
  42. });
  43. console.log(response);

コンソール

  1. PUT /transactions/_bulk?refresh
  2. {"index":{"_id":1}}
  3. {"type": "sale","amount": 80}
  4. {"index":{"_id":2}}
  5. {"type": "cost","amount": 10}
  6. {"index":{"_id":3}}
  7. {"type": "cost","amount": 30}
  8. {"index":{"_id":4}}
  9. {"type": "sale","amount": 130}

ドキュメント1と3がシャードAに、ドキュメント2と4がシャードBに配置されるとしましょう。以下は、上記の例の各段階での集約結果の内訳です。

init_scriptの前

state は新しい空のオブジェクトとして初期化されます。

Js

  1. "state" : {}

init_scriptの後

これは、ドキュメントの収集が行われる前に各シャードで1回実行され、各シャードにコピーが作成されます:

  • シャードA

Js

  1. "state" : {
  2. "transactions" : []
  3. }
  • シャードB

Js

  1. "state" : {
  2. "transactions" : []
  3. }

map_scriptの後

各シャードはドキュメントを収集し、収集された各ドキュメントに対して map_script を実行します:

  • シャードA

Js

  1. "state" : {
  2. "transactions" : [ 80, -30 ]
  3. }
  • シャードB

Js

  1. "state" : {
  2. "transactions" : [ -10, 130 ]
  3. }

combine_scriptの後

combine_script は、ドキュメントの収集が完了した後、各シャードで実行され、すべてのトランザクションを単一の利益数値に減少させます(トランザクション配列内の値を合計することによって)これがコーディネーティングノードに渡されます:

  • シャードA
  • 50
  • シャードB
  • 120

reduce_scriptの後

reduce_script は、各シャードの combine スクリプトの結果を含む states 配列を受け取ります:

Js

  1. "states" : [
  2. 50,
  3. 120
  4. ]

シャードの応答を最終的な全体の利益数値に減少させ(値を合計することによって)、これを集約の結果として返します。

Js

  1. {
  2. ...
  3. "aggregations": {
  4. "profit": {
  5. "value": 170
  6. }
  7. }
  8. }

その他のパラメータ

params オプション。init_scriptmap_script、および combine_script に変数として渡される内容を持つオブジェクトです。これは、ユーザーが集約の動作を制御し、スクリプト間で状態を保存できるようにするために役立ちます。これが指定されていない場合、デフォルトは次の提供と同等です:
#### Js
{$pre20}

空のバケット

スクリプトメトリック集約の親バケットがドキュメントを収集しない場合、null 値を持つ空の集約応答がシャードから返されます。この場合、reduce_scriptstates 変数は、そのシャードからの応答として null を含みます。したがって、reduce_script はシャードからの null 応答を期待し、対処する必要があります。