本地英文版地址: ../en/search-aggregations-metrics-scripted-metric-aggregation.html
使用脚本执行以提供度量输出的度量聚合。
示例:
POST ledger/_search?size=0 { "query" : { "match_all" : {} }, "aggs": { "profit": { "scripted_metric": { "init_script" : "state.transactions = []", "map_script" : "state.transactions.add(doc.type.value == 'sale' ? doc.amount.value : -1 * doc.amount.value)", "combine_script" : "double profit = 0; for (t in state.transactions) { profit += t } return profit", "reduce_script" : "double profit = 0; for (a in states) { profit += a } return profit" } } } }
上面的聚合演示了如何使用脚本聚合来计算销售和成本交易的总利润。
其响应如下:
{ "took": 218, ... "aggregations": { "profit": { "value": 240.0 } } }
在上面的例子中也可以指定存储的脚本,如下所示:
POST ledger/_search?size=0 { "aggs": { "profit": { "scripted_metric": { "init_script" : { "id": "my_init_script" }, "map_script" : { "id": "my_map_script" }, "combine_script" : { "id": "my_combine_script" }, "params": { "field": "amount" }, "reduce_script" : { "id": "my_reduce_script" } } } } }
有关指定脚本的更多详细信息,请参考脚本文档。
虽然在单个脚本中可以使用任何有效的脚本对象,但是脚本必须在 state
对象中仅返回或存储以下类型:
- 原始类型(primitive types)
- 字符串(string)
- 映射(map,仅包含此处列出的类型的键和值)
- 数组(array,仅包含此处列出的类型的元素)
脚本化度量聚合在其执行的 4 个阶段中使用脚本:
- init_script
-
在收集任何文件之前执行。允许聚合设置任何初始状态。
在上面的例子中,
init_script
在state
对象中创建了一个数组transactions
。 - map_script
-
每个收集的文档执行一次。这是一个必需的脚本。如果没有指定
combine_script
,那么结果状态需要存储在state
对象中。在上面的示例中,
map_script
检查type
字段的值。 如果值为sale,则amount
字段的值将被添加到transactions
数组中。 如果type
字段的值不是sale,则将amount
字段取反的值添加到transactions
中。 - combine_script
-
文档收集完成后,在每个分片上执行一次。这是一个必需的脚本。允许聚合合并从每个分片返回的状态。
在上面的例子中,
combine_script
遍历所有存储的transactions
,对profit
变量中的值求和,最后返回profit
。 - reduce_script
-
在所有分片返回结果后,在协调节点上执行一次。 这是一个必需的脚本。 该脚本提供了对变量
states
的访问,该变量是每个分片上的 combine_script 结果的数组。在上面的例子中,
reduce_script
遍历每个分片返回的profit
,对这些值求和,然后返回最终的组合的 profit(利润),该利润将在聚合的响应中返回。
设想这样一种情况,你将下面的文档索引到一个包含两个分片的索引中:
PUT /transactions/_bulk?refresh {"index":{"_id":1}} {"type": "sale","amount": 80} {"index":{"_id":2}} {"type": "cost","amount": 10} {"index":{"_id":3}} {"type": "cost","amount": 30} {"index":{"_id":4}} {"type": "sale","amount": 130}
假设文档1和3最终在分片A上,文档2和4最终在分片B上。 下面是上例中每个阶段的汇总结果。
在执行任何文档收集之前,这将在每个分片上运行一次,因此我们将在每个分片上有一个副本:
- 分片 A
-
"state" : { "transactions" : [] }
- 分片 B
-
"state" : { "transactions" : [] }
每个分片收集它的文档,并在收集的每个文档上运行 map_script:
- 分片 A
-
"state" : { "transactions" : [ 80, -30 ] }
- 分片 B
-
"state" : { "transactions" : [ -10, 130 ] }
在文档收集完成后,在每个分片上执行 combine_script,并将所有 transactions 减少到每个分片的单个利润数字(通过对 transactions 数组中的值求和),该数字被传递回协调节点:
- 分片 A
- 50
- 分片 B
- 120
params |
可选的。
一个对象,其内容将作为变量传递给 "params" : {} |