Bucket script aggregation #
A parent pipeline aggregation computing arithmetic on a bucket’s own
metrics — the script references sibling metrics by name through
params and its result becomes a new per-bucket value. It is the
SQL SELECT a / b AS c of the aggregation world: one derived column,
evaluated once per bucket over values the bucket already holds.
"avg_order": {
"bucket_script": {
"buckets_path": { "r": "revenue", "n": "orders" },
"script": "params.r / params.n"
}
}
How it works #
bucket_script is declared inside the multi-bucket aggregation it
decorates, next to the metrics it consumes. After the buckets are
built, the engine resolves each named path against every bucket,
binds the numbers into the script’s scope, evaluates the script once,
and inserts its result under the pipeline’s own name — the
response shape buckets[i].avg_order.value.
Details verified against the engine:
buckets_pathis a map of script variable names to sibling metric paths:{ "r": "revenue", "n": "orders" }. A.valuesuffix and"_count"(the bucket’s document count) also resolve. A plain string instead of a map binds a single variable named_value.- Each variable is reachable two ways —
params.rand barer. Values arrive as floats. - A gap (a named metric missing in that bucket) yields a
nullvalue; the bucket itself stays in the response. - A runtime failure or a non-numeric result also yields
nullfor that bucket — never a dropped bucket, never a failed request. - The script’s last expression is its result; integer division
truncates (
5 / 2is2), so keep a.0on literals — see pipeline scripts. - A second, engine-specific placement also works: declaring
bucket_scriptnext to the bucket aggregation, with fullparent>metricpaths ({ "s": "by_cat>sum_p" }), returns a standalone buckets array carrying onevalueper bucket; under the defaultskippolicy, buckets with gaps are dropped from that output.
Examples #
The teaching dataset sells exactly once per day, so every day’s
avg_order equals that day’s single amount — the more interesting
shape appears over terms buckets: per product type the four
revenues 1800, 1800, 1350, 1800 over 60, 30, 20, 10 orders give
average order values of 30, 60, 67.5, 180.
Use cases #
- Average order value —
revenue / ordersper bucket, the classic derived commerce metric, without post-processing. - Ratios and rates — conversion (converted / total), error rate (errors / requests), fill rate — any numerator/denominator pair the bucket already computed.
- Unit economics —
revenue / quantityfor price-per-unit, margin expressions when cost lives in another sub-agg. - Threshold flags —
if params.r > 1000 { 1.0 } else { 0.0 }marks buckets for downstream counting or alerting. - Scripted quality scores — weighted combinations
(
0.4 * params.a + 0.6 * params.b) that rank buckets by design.
Parameters for bucket_script
#
buckets_path
(Required, object) Map of script variable names to sibling metric paths ({ "r": "revenue" }); a plain string binds_value.script
(Required, string) Expression overparams.<name>(or the bare<name>) — see pipeline scripts.gap_policy
(Optional, string)skip(default) orinsert_zeros— effective in the sibling placement; nested, a gap always yields anullvalue and keeps the bucket.
Related #
bucket_selector— the same machinery as a keep/drop predicate instead of a metricmoving_fn— scripts over a window of buckets rather than one bucket’s siblings- pipeline scripts — the script language reference