如何在OpenSearch中创建争议嵌套交易求和值的直方图?
问题描述
我正在使用OpenSearch索引,每个文档代表一起争议,包含嵌套的交易数组。目标是计算每起争议中嵌套交易数组内transactions.transactionAmount.amountInCents字段的总和,再基于这些求和值创建直方图。
文档结构示例:
{ "dispute_id": "123", "transactions": [ { "transactionMerchant": "MerchantA", "transactionAmount": { "amountInCents": 1000, "currency": "USD" } }, { "transactionMerchant": "MerchantB", "transactionAmount": { "amountInCents": 2000, "currency": "USD" } } ] }
已尝试操作
已成功编写查询计算每起争议的交易金额总和:
POST /dispute/_search { "size": 0, "aggs": { "by_dispute": { "terms": { "field": "dispute_id", "size": 10 }, "aggs": { "nested_transactions": { "nested": { "path": "transactions" }, "aggs": { "transaction_sum": { "sum": { "field": "transactions.transactionAmount.amountInCents" } } } } } } } }
该查询能正确返回每起争议的求和值,但尝试创建直方图时遇到嵌套聚合的限制,无法直接引用子聚合的结果。
失败尝试
尝试直接在顶级聚合中添加直方图,引用子聚合的值,但返回空桶:
POST /dispute/_search { "size": 0, "aggs": { "by_dispute": { "terms": { "field": "dispute_id", "size": 10 }, "aggs": { "nested_transactions": { "nested": { "path": "transactions" }, "aggs": { "transaction_sum": { "sum": { "field": "transactions.transactionAmount.amountInCents" } } } } } }, "sum_histogram": { "histogram": { "field": "by_dispute>nested_transactions>transaction_sum.value", "interval": 1000 } } } }
返回结果片段:
"sum_histogram": { "buckets": [] }
解决方案
OpenSearch不支持直接在顶级聚合中引用子聚合的计算结果,需要使用**管道聚合(Pipeline Aggregation)**中的histogram_bucket来基于by_dispute聚合桶中的求和值生成直方图。
正确查询示例
POST /dispute/_search { "size": 0, "aggs": { "by_dispute": { "terms": { "field": "dispute_id", "size": 10000 // 根据实际争议数量调整,确保覆盖所有数据 }, "aggs": { "nested_transactions": { "nested": { "path": "transactions" }, "aggs": { "transaction_sum": { "sum": { "field": "transactions.transactionAmount.amountInCents" } } } }, // 将嵌套聚合的求和值提取到争议桶层面 "dispute_total": { "bucket_script": { "buckets_path": { "total": "nested_transactions>transaction_sum" }, "script": "params.total" } } } }, // 基于每个争议的求和值生成直方图 "sum_histogram": { "histogram_bucket": { "buckets_path": "by_dispute>dispute_total", "interval": 1000, "keyed": true } } } }
关键说明
- bucket_script聚合:将嵌套聚合中计算出的
transaction_sum提取到by_dispute的桶层面,生成dispute_total字段,为后续管道聚合提供可引用的数值。 - histogram_bucket管道聚合:遍历
by_dispute的所有桶,将每个桶的dispute_total值按照指定的interval(此处为1000分)分组,生成直方图的各个桶。 - size参数调整:
by_dispute聚合的size必须设置足够大,确保能包含所有争议文档,否则会丢失部分数据,导致直方图结果不准确。
替代方案:使用运行时字段优化性能
如果数据量较大,管道聚合的性能无法满足需求,可以在索引中添加运行时字段,提前计算每个争议的交易金额总和,之后直接对该字段做直方图聚合:
定义运行时字段(索引级别)
PUT /dispute/_mapping { "runtime": { "total_transaction_amount": { "type": "long", "script": { "source": "def sum = 0; if (params._source.transactions != null) { for (t in params._source.transactions) { sum += t.transactionAmount.amountInCents; } } return sum;" } } } }
直接生成直方图
POST /dispute/_search { "size": 0, "aggs": { "sum_histogram": { "histogram": { "field": "total_transaction_amount", "interval": 1000 } } } }
该方案的优势是查询时无需嵌套和管道聚合,性能更优,脚本中也处理了transactions数组为空的边界情况。
内容的提问来源于stack exchange,提问作者Shahriar
相关产品推荐
相关产品推荐

