Moving avg aggregation #
A parent pipeline aggregation smoothing a metric with a moving average over the last N buckets — one averaged point per bucket, flattening noise so the trend underneath shows.
"smooth": {
"moving_avg": { "buckets_path": "per_day>revenue", "window": 3 }
}
How it works #
In this engine moving_avg is evaluated in the sibling
placement: declare it next to the bucket aggregation and point
buckets_path at the series with the full parent>metric form. After
the buckets are built, the engine slides a trailing window over
their values and emits a standalone buckets array (keys 0..n−1)
with one value per consumed bucket — the average of the window
ending at that bucket.
- The window is truncated at the start of the series: the first bucket averages just itself, the second at most two values.
windowdefaults to5;0is treated as1; a negative or fractional value is rejected when the request parses.- Gaps follow
gap_policy:skip(default) leaves empty buckets out of the series before averaging;insert_zeroscontributes0.
Three models are implemented, chosen by model:
| Model | Behavior |
|---|---|
simple (default) | Plain arithmetic mean of the window. |
linear | Weighted mean, weights rising 1..n — the newest value weighs the most. |
ewma | Exponentially weighted average s = α·x + (1−α)·s, seeded with the oldest window value; α comes from settings.alpha, default 0.3. |
holt and holt_winters are accepted for compatibility but
currently fall back to the simple mean — double/triple
exponential smoothing is not implemented. Executed example over the
series 60, 150, 150: simple window 3 gives 60, 105, 120;
linear window 2 gives 60, 120; ewma window 2 gives 60, 87, 150, and ewma with alpha: 1.0 degenerates to the newest value.
The nested placement — moving_avg declared inside the
histogram’s aggs with a bare buckets_path — parses but is not
wired to the nested injection path yet: every bucket’s entry stays
null. Use the sibling form above, or
moving_fn,
which works nested.
This engine still computes moving_avg.
Examples #
The teaching dataset sells exactly once per day, so each smoothed
point is the mean of that day’s amount and the two before it —
smooth.buckets[i].value tracks the trailing 3-day average while
per_day keeps the raw daily figure.
Use cases #
- Dashboard smoothing — raw daily revenue jitters; the trailing average is the line people actually read trend from.
- Trend baseline for alerting — compare the current bucket against the moving average instead of yesterday’s outlier.
- Recent-weighted health signals —
ewmawith a higheralphareacts faster to shifts, catching regime changes a plain mean dilutes. - Pre-smoothing before differencing — feed the smoothed series
into
derivative/serial_diffto difference signal, not noise.
Parameters for moving_avg
#
buckets_path
(Required, string) Path to the consumed series:"<bucket_agg>><metric>"(sibling placement).window
(Optional, integer, default:5) Number of buckets in the sliding window; clamped to a minimum of1.model
(Optional, string, default:simple)simple,linearorewma;holt/holt_wintersfall back tosimple.settings
(Optional, object) Model settings —alphaforewma(default0.3).gap_policy
(Optional, string)skip(default) orinsert_zeros.
Related #
moving_fn— the general window statistic behind every model here (any script overvalues); also works nestedderivativeandserial_diff— change instead of levelavg_bucket— one mean over all buckets, not a sliding one