What Are Bucket Aggregations?
Bucket aggregations group the documents matching a query into buckets based on some criterion, and unlike metric aggregations they don't produce a number by themselves, they produce a set of buckets, each with a doc_count and, optionally, nested sub-aggregations. The most common bucket types are terms, which creates a bucket per unique field value, range and date_range, which bucket by explicit boundaries, and histogram and date_histogram, which bucket by fixed-size intervals.
Cricket analogy: It's like grouping a season's matches by opponent, one bucket per team India played, then counting matches in each, the way a broadcaster segments a bilateral series review.
Terms and Range Buckets
The terms aggregation creates one bucket per unique value of a keyword, numeric, or IP field, ordered by doc_count by default, and its size parameter controls how many top buckets are returned; because terms aggregations run per-shard before being merged on the coordinating node, the response includes doc_count_error_upper_bound, an indication of how much the counts could be off when the true top-N spans shards unevenly. The range aggregation instead lets you define explicit numeric bucket boundaries, such as price bands, and date_range does the same for date fields.
Cricket analogy: It's like a terms aggregation on 'bowler' returning the top wicket-takers in a series, while a range bucket groups scores into bands: 0-29, 30-49, 50-plus, the way a scorecard summarizes a Kohli innings distribution.
GET /products/_search
{
"size": 0,
"aggs": {
"by_category": {
"terms": { "field": "category.keyword", "size": 10 },
"aggs": {
"avg_price": { "avg": { "field": "price" } }
}
}
}
}Date Histogram and Histogram
The date_histogram aggregation buckets documents into fixed time intervals using calendar_interval (day, week, month, quarter, year, which respect variable month lengths and daylight saving) or fixed_interval (a strict duration like 90m or 12h). The plain histogram aggregation does the equivalent for numeric fields, bucketing values into equal-width ranges you specify with the interval parameter, and both support extended_bounds to force empty buckets to appear at the edges of a range rather than being silently omitted.
Cricket analogy: It's like bucketing a batter's scores by month across a season, using calendar_interval to respect that April and June aren't the same length, the way a form-tracking graph is built.
Use min_doc_count: 0 together with extended_bounds to make date_histogram or histogram return empty buckets across the full requested range, which is essential for rendering continuous time-series charts where gaps would otherwise be silently dropped from the response.
Nesting Sub-Aggregations
Any bucket aggregation can contain nested aggregations, whether more bucket aggregations for multi-level grouping or metric aggregations that compute a statistic within each bucket, and Elasticsearch evaluates this whole tree in a single request rather than requiring N+1 round trips. This is what makes the aggregation framework function like a pivot table: a terms aggregation on category nested with a date_histogram on order_date nested with an avg on total_price produces category-by-month average order value in one query.
Cricket analogy: It's like nesting a per-bowler breakdown inside a per-innings bucket inside a per-match bucket, producing a full three-level scorecard analysis in one pass, the way ESPNcricinfo's Statsguru builds cross-tab reports.
The terms aggregation's accuracy across shards depends on shard_size (how many candidate buckets each shard returns before merging) and the actual data distribution; if a term is common on one shard but rarely appears in top results on others, the reported top-N and doc_count_error_upper_bound can understate the true count. Increasing shard_size, or routing data to reduce shard fragmentation, improves accuracy at the cost of more per-shard work.
- Bucket aggregations group matched documents into buckets by criteria (terms, range, date_range, histogram, date_histogram) rather than producing a single number.
- The terms aggregation buckets by unique field value and returns doc_count_error_upper_bound to flag potential inaccuracy from shard-level merging.
- date_histogram supports calendar_interval (respects variable month/year lengths) and fixed_interval (strict durations).
- min_doc_count: 0 with extended_bounds fills in empty buckets so time-series charts don't have gaps.
- Bucket aggregations can nest arbitrarily deep, combining more buckets and metric aggregations into a single pivot-table-style query.
- shard_size controls how many candidate terms each shard returns before the coordinating node merges results, affecting top-N accuracy.
- A single aggregation request can replace what would otherwise require multiple round-trip queries against the same dataset.
Practice what you learned
1. What distinguishes a bucket aggregation from a metric aggregation?
2. What does doc_count_error_upper_bound in a terms aggregation response indicate?
3. Which interval type in date_histogram correctly accounts for months having different numbers of days?
4. What is the purpose of combining min_doc_count: 0 with extended_bounds?
5. In a nested aggregation like terms > date_histogram > avg, what does this structure achieve?
Was this page helpful?
You May Also Like
Metric Aggregations
Learn how Elasticsearch's metric aggregations compute single- and multi-value numeric summaries like avg, sum, cardinality, and percentiles over matched documents.
Nested Aggregations
Learn how the nested and reverse_nested aggregations let Elasticsearch correctly aggregate over arrays of objects mapped with the nested field type.
Aggregations vs SQL GROUP BY
Compare Elasticsearch's aggregation framework to SQL's GROUP BY and aggregate functions, covering conceptual mapping, execution model differences, and when to prefer each.
Aggregation Performance
Learn what drives aggregation performance in Elasticsearch, doc_values, shard sizing, caching, and approximate algorithms, and how to keep large aggregations fast.