Scripted metric aggregation

Scripted metric aggregation #

A metrics aggregation whose result is computed by your own scripts, in four phases, running on Pizza’s sandboxed script engine (see the script language reference).

How it works #

One state map per segment, folded once at the end:

PhaseRunsScope
init_scriptonce per segmentstate, params
map_scriptonce per documentstate, doc, params
combine_scriptonce per segmentstate, params
reduce_scriptonce, at the endstates, params

state is a map you own — initialize it in init_script, accumulate into it in map_script. combine_script folds one segment’s state into a single value (a script that ends in a statement returns the state itself, the default when combine_script is omitted). reduce_script receives all combined values as the states array; if it is omitted, a single state passes through unchanged and several come back as an array — the parts, rather than a wrong merge. Builds without the scripting feature return null for the whole aggregation.

Document fields are reachable in the doc-values shape:

  • doc.price.value — the first value of price for the current document
  • doc.price.values — all values (multi-value fields)
  • doc['price'].value — the bracket spelling
  • a field the document doesn’t have has no entry — doc.missing.value errors

Example: total and average order value #

Total revenue, order count and average order value in one pass (120 docs, total 6750, average 56.25 on the sample data):

Example: filtered sum with params #

Only hat orders count; params carries the filter value (all four phases see params). On the sample data: 1800 over 30 orders.

Use cases #

  • One pass, several metrics — total, count and average in a single sweep, or any bundle of dependent numbers a plain metric agg cannot produce together.
  • Filtered accumulation — count or sum only the rows a params value selects (the hat revenue above), without a wrapping filter bucket.
  • Custom metrics — medians-of-groups, per-key tallies (state.by_type[x] += 1), or any shape a map plus a reduce can hold, when no built-in agg fits.
  • Multi-state reductions — collect a list per segment and merge the lists in reduce_script, the pattern for top-N-by-group inside a script.

Parameters #

NameTypeDescription
init_scriptstringSets up the initial state. Optional.
map_scriptstringExecuted per document. Optional (a doc-count-only agg needs none).
combine_scriptstringFolds a segment’s state to one value. Defaults to the state.
reduce_scriptstringFolds the states array to the result. See below.
paramsobjectExtra variables visible in every phase as params.<name>.

Notes and limits #

  • Language: scripts are Rhai, not Painless. Everything in the language reference applies — in particular there is no ?: ternary and strings use double quotes (doc['x'] single-quoted refs are rewritten for you). state.list arrays work with push: state.items.push(doc.price.value) mutates the state, not a copy.
  • Distributed: under fan-out each shard returns its combined values; the coordinator runs reduce_script over them in shard-arrival order; a reduce_script that is not order-independent (non-commutative) is the script author’s problem.
  • Cost: map_script runs once per matched document at roughly two microseconds per document. Keep it small; a sum agg with field is always faster than a scripted sum.
  • Errors in any phase abort the aggregation and come back as {"error": "<phase>: <message>"} rather than a wrong number.
  • The single-value metric aggs (sum, avg, …) also accept a per-doc script as their value source — see scripted value sources. Use scripted_metric when one script must see the whole bucket shape (filters, multi-state reductions), the plain metric script when one expression per doc is enough.
  • Pipeline scripts — the Rhai language reference: syntax, doc/params bindings, and the limits of the sandbox.
  • Scripted value sources — the cheaper per-document script form on sum, avg, min, max, value_count and cardinality.
  • bucket_script — a script over bucket metrics (after the aggregation), where scripted_metric scripts run per document (during it).
Calendar October 6, 2026
Edit Edit this page