Percentiles bucket aggregation

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, …). A stats sub-agg contributes its sum. A bare parent name profiles the buckets’ doc_counts.
  • skip (default) leaves buckets with a missing metric — and empty buckets (doc_count 0) whose sum reads 0 — out of the sample; insert_zeros has them contribute 0.

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 terms aggregation, 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) or insert_zeros.
  • format
    Not a parameter of this aggregation in the current engine — accepted for compatibility and ignored; values are returned unformatted.
Calendar October 6, 2026
Edit Edit this page