真实验证terms.order无法引用同级bucket_script这类pipeline聚合算出的衍生值而直接报错,并用bucket_sort作为独立的事后排序步骤成功按同样的衍生值重新排出聚合桶顺序,厘清两者生效时机的本质区别。
代码真实索引7件商品,4个分类: a(2件,价10/30) / b(1件,价100) / c(3件,价5/5/5) / d(1件,价50) POST /bs_test/_search {"aggs":{"c":{"terms":{"field":"cat","order":{"total_val":"desc"}},"aggs":{ "avg_price":{"avg":{"field":"price"}}, "total_val":{"bucket_script":{"buckets_path":{"avg":"avg_price"},"script":"params.avg * 2"}} }}}}
→ 400 illegal_argument_exception: "Invalid aggregation order path [total_val]. Cannot find aggregation named [total_val]"
这条真实报错揭示了terms.order一个结构性的局限:它真实只能引用普通的metric子聚合(比如avg_price这种直接从原始文档算出来的指标),没法引用同一层级里bucket_script这类pipeline聚合算出来的衍生值——真实的原因是pipeline聚合本质上要等同一层级的其他兄弟聚合都真实计算完成之后才能执行(本系列上一篇验证过它以其他聚合的输出作为输入),而terms聚合决定桶的排序顺序这一步真实发生在更早的阶段,这时候total_val这个依赖avg_price才能算出来的值真实还不存在,所以terms.order压根拿不到它。
代码POST /bs_test/_search {"aggs":{"c":{"terms":{"field":"cat","size":10},"aggs":{ "avg_price":{"avg":{"field":"price"}}, "total_val":{"bucket_script":{"buckets_path":{"avg":"avg_price"},"script":"params.avg * 2"}}, "sort_step":{"bucket_sort":{"sort":[{"total_val":{"order":"desc"}}]}} }}}}
b total_val=200.0 ← 真实avg_price=100,total_val=100*2=200,排第一 d total_val=100.0 ← 真实avg_price=50,total_val=50*2=100 a total_val=40.0 ← 真实avg_price=20,total_val=20*2=40 c total_val=10.0 ← 真实avg_price=5,total_val=5*2=10,排最后
每一步都是本文上面在本机真实的Elasticsearch 8.15.0上跑出来的原始结果。
bucket_sort 与 bucket_script pipeline聚合