Percentiles bucket aggregation #
A sibling pipeline aggregation computing percentiles of a metric across
buckets — e.g. “the daily-revenue p95”. The mean of the per-bucket
values answers “what is typical”; percentiles answer “what the whole
ladder of buckets looks like” — including the outlier end that a
stats_bucket min/max flattens into two numbers.
"day_pcts": { "percentiles_bucket": { "buckets_path": "per_day>revenue" } }
How it works #
percentiles_bucket is declared next to the bucket aggregation it
consumes and runs after every regular aggregation — including the
distributed merge — has finished. It walks the parent’s finished
buckets, collects one number per bucket, sorts them, and evaluates each
requested percentile over the sorted sample, returning a
{"values": {...}} object keyed by the percentile:
{
"values": { "1": 15, "5": 15, "25": 30, "50": 45,
"75": 75, "95": 180, "99": 180 }
}
Quantile estimation follows TDigest semantics with every bucket value
acting as a weight-1 centroid. For n values the estimate for
percentile p is taken at position p / 100 × n in the sorted list:
a position landing exactly between two centroids returns their
mean, a position inside centroid k returns that centroid’s
value, and positions off either end clamp to the minimum or maximum.
The median of 100, 200, 300 is 200; their p40 is also 200 (the
position 1.2 falls inside the 200 centroid).
The buckets_path and gap rules are the family’s:
"per_day>revenue"(>or.separator) — the sub-metric inside each bucket; it must be single-valued (sum,avg,min,max,value_count,cardinality, …). Astatssub-agg contributes itssum. A bare parent name profiles the buckets’doc_counts.skip(default) leaves buckets with a missing metric — and empty buckets (doc_count0) whosesumreads0— out of the sample;insert_zeroshas them contribute0.
With no contributing bucket the result is {"values": {}}.
Examples #
Half of the 120 selling days bring 45 or less, while the top few
percent spike to 180 — a long-tailed distribution an average alone
would hide.
Use cases #
- Typical-vs-tail revenue — p50 versus p95 of daily revenue: the gap between them is the “good day” premium.
- SLA across groups — p95/p99 of the per-service average latencies
of a
termsaggregation, the standard way to report tail latency. - Spot skewed group totals — percentiles of per-category sums: a p95 close to the max means one category dominates.
- Robust baseline — the median across buckets resists the outlier
days that drag
avg_bucket.
Parameters for percentiles_bucket
#
buckets_path
(Required, string) Path to the consumed metric.percents
(Optional, number array) Percentiles to compute; defaults to[1, 5, 25, 50, 75, 95, 99].gap_policy
(Optional, string)skip(default) orinsert_zeros.format
Not a parameter of this aggregation in the current engine — accepted for compatibility and ignored; values are returned unformatted.
Related #
- Sibling family:
avg_bucket,sum_bucket,min_bucket,max_bucket,stats_bucket,extended_stats_bucket - Document-level counterpart:
percentiles