Histogram aggregation #
A multi-bucket aggregation over numeric fields that applies a fixed interval to build the buckets. It answers “how are the values distributed?” — every document lands in exactly one bucket, and the bucket keys form a regular grid over the value axis.
How it works #
Each document’s value v is placed by index arithmetic — bucket index
floor((v - offset) / interval) — so a bucket covers the half-open
window [key, key + interval). Buckets accumulate in a sorted map, and
the response lists them by ascending key.
With the default min_doc_count: 0, every bucket between the data
minimum and maximum is materialized — gaps inside the data extent come
back with doc_count: 0 (the fill is capped at 65,536 buckets).
extended_bounds may only widen that fill range, never shrink it;
hard_bounds clips it, drops buckets that fall entirely outside
[min, max], and force-materializes the full in-window grid even at
zero documents. offset slides the whole grid along the value axis
(boundaries become k · interval + offset).
Each bucket reports key (the window’s lower bound, a number) and
doc_count; the columnar path additionally renders key_as_string by
reading the key as epoch milliseconds in strict ISO form — meaningful
when the numeric field actually stores dates.
Examples #
Prices are 15/30/45/60, so an interval of 25 makes three buckets —
HISTOGRAM(price, 25) on the SQL side:
POST /sales/_search
{
"aggs": {
"prices": {
"histogram": {
"field": "price",
"interval": 50
}
}
}
}
Response:
{
...
"aggregations": {
"prices": {
"buckets": [
{ "key": 0.0, "doc_count": 110 },
{ "key": 50.0, "doc_count": 10 }
]
}
}
}
Parameters for histogram
#
field
(Required, string) Field you wish to aggregate (must be numeric).interval
(Required, number) Bucket width.offset
(Optional, number, default:0.0) Shift the bucket boundaries.min_doc_count
(Optional, integer, default:0) Only return buckets with at least this many documents.hard_bounds
(Optional, object) Restrict bucket generation to[min, max)— buckets fully outside are dropped even withmin_doc_count: 0.extended_bounds
(Optional, object) Widen the bucket range beyond the data extent (empty buckets are materialized up to these bounds whenmin_doc_countis0). Can only extend, never shrink below the data extent.aggs
(Optional, object) Nested sub-aggregations, computed per bucket.
Range fields #
Histograms (and date histograms) accept _range field types
(integer_range, long_range, double_range, date_range, …): a
document’s stored range counts in EVERY bucket it overlaps — the bucket
window [from, to) and the stored range intersect — rather than in the
single bucket holding its midpoint. Open-ended sides ({"lte": 10},
{"gte": 15}) extend to the histogram’s hard_bounds window, which
also force-materializes every in-window bucket even at zero documents.
POST /my-collection/_search
{
"size": 0,
"aggs": {
"histo": {
"histogram": {
"field": "range",
"interval": 1,
"hard_bounds": { "min": 0, "max": 20 }
}
}
}
}
Use cases #
- Price-band analysis. Fixed-width bands over a
price-style field are the backbone of merchandising reports. Over the teaching dataset’s 120 sales an interval of 50 yields two buckets — 110 sales under 50, 10 at 50 and above. - Distribution sketches. Where do values cluster, and how thick is the tail? A histogram with a small interval is the cheapest density estimate the engine offers; follow up with percentiles for exact quantiles.
- Time-as-number timelines. Fields stored as epoch milliseconds can
be bucketed directly (the fast path renders each
key_as_stringas an ISO timestamp); for calendar-aware windows prefer the date histogram. - Zero-filled chart axes.
min_doc_count: 0plusextended_boundsproduces the contiguous, gap-free bucket series a charting front-end needs, without padding client-side.
Related #
date_histogram— the same fixed-grid idea over date fields, with calendar-aware intervals.auto_date_histogram— you pick the bucket count, the engine picks the interval.variable_width_histogram— bucket edges adapt to the data instead of staying fixed.range— a handful of hand-named, possibly overlapping bands instead of a regular grid.