5.1.11. 脚本式指标聚合
脚本式指标聚合
使用脚本执行以提供度量标准输出的度量标准聚合。
例子:
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"
}
}
}
}
init_script
是可选参数,所有其他脚本都是必需的。
以上聚合演示了如何使用脚本汇总来计算销售和成本交易的总利润。
以上聚合的响应:
{
"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"
}
}
}
}
}
- 必须在全局 params 对象中指定
init
,map
和合并脚本的脚本参数,以便可以在脚本之间共享。
有关指定脚本的更多详细信息,请参见脚本文档.
允许的返回类型
虽然任何有效的脚本对象都可以在一个脚本中使用,但脚本必须返回或存储在state
对象中只有以下类型:
- 基本类型
- 字符串
- 映射 (只包含此处列出的类型的键和值)
- 数组 (仅包含此处列出的类型的元素)
脚本范围
脚本度量聚合在执行的4个阶段使用脚本:
init_script
在收集任何文件之前执行。允许聚合设置任何初始状态。
在上面的示例中,init_script
在state
对象中创建一个数组transactions
。map_script
每个收集的文档执行一次。这是必需的脚本。如果未指定combine_script
,则需要将结果状态存储在state
对象中。
在上面的示例中,map_script
检查类型字段的值。如果值为 sale,则金额字段的值将添加到交易数组中。如果类型字段的值不是 sale,则金额字段的取反值将添加到交易中。
combine_script
文档收集完成后,对每个分片执行一次。这是必需的脚本。允许聚合合并从每个分片返回的状态。
在上面的示例中,
combine_script
遍历所有存储的交易,对profit
变量中的值求和,最后返回profit
。reduce_script
所有分片均返回其结果后,在协调节点上执行一次。这是必需的脚本。该脚本可以访问变量
states
,该变量是每个分片上 combine_script 结果的数组。在上面的示例中,
reduce_script
通过每个分片返回的profit
进行迭代,然后在返回最终的合并利润之前返回每个合并的值,该合并后的利润将被返回。
工作示例
想象一下您将以下文档编入带有2个分片的索引的情况
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上。以下是上述示例各阶段汇总结果的细目分类。
初始化 init_script
state
被初始化为新的空对象。
"state" : {}
初始化 init_script 后
在执行任何文档收集之前,此操作在每个分片上运行一次,因此我们在每个分片上都有一个副本:
分片 A
"state" : { "transactions" : [] }
分片 B
"state" : { "transactions" : [] }
map_script 后
每个分片都会收集其文档,并在收集到的每个文档上运行 map_script:
分片 A
"state" : { "transactions" : [ 80, -30 ] }
分片 B
"state" : { "transactions" : [ -10, 130 ] }
combine_script 之后
在文档收集完成之后,对每个分片执行 combine_script,并将每个分片的所有交易降低为单个利润数字(通过对交易数组中的值求和),然后将其传递回协调节点:
分片 A
50
分片 B
120
reduce_script 之后
reduce_script 接受另一个 states
数组,其中包含每个分片的合并脚本的结果:
"states" : [
50,
120
]
它将分片的响应降低到最终的总利润数字(通过对值求和),并将其作为聚合结果返回以产生响应:
{
...
"aggregations": {
"profit": {
"value": 170
}
}
}
其他参数
- params
可选的。一个对象,其内容将作为变量传递到init_script
,map_script
和combine_script
。这对于允许用户控制聚合的行为以及在脚本之间存储状态很有用。如果未指定,则默认等效于提供:"params" : {}
空桶
如果脚本化指标聚合的父桶未收集任何文档,则分片将返回空聚合响应,并带有null
值。在这种情况下,reduce_script
的status
变量将包含null
作为该分片的响应。因此,reduce_script
应该期望并处理分片的null
响应。
本译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。