Elasticsearch Aggregations
Aggregations let you analyze data instead of just searching it. They power dashboards, charts, and reports — answering questions like "how many products per category?" or "what is the average order value this month?"
Search vs Aggregation
Search: "Find all products with name matching headphones"
→ Returns a list of matching documents
Aggregation: "How many products exist per category?"
→ Returns summarized numbers, not documents
Both can run together in a single request.
Three Types of Aggregations
| Type | What It Does | Example Output |
|---|---|---|
| Metric | Calculates a number from field values | Average price: 1,499 |
| Bucket | Groups documents into buckets | Electronics: 42 docs, Clothing: 18 docs |
| Pipeline | Runs calculations on other aggregation results | Month with highest average order value |
Metric Aggregations
Metric aggregations compute values like sum, average, min, max, and count.
GET /products/_search
{
"size": 0,
"aggs": {
"average_price": { "avg": { "field": "price" } },
"max_price": { "max": { "field": "price" } },
"min_price": { "min": { "field": "price" } },
"total_revenue": { "sum": { "field": "price" } },
"product_count": { "value_count": { "field": "price" } }
}
}
size: 0 tells Elasticsearch not to return individual documents — only the aggregation results.
Response:
"aggregations": {
"average_price": { "value": 1249.5 },
"max_price": { "value": 85000 },
"min_price": { "value": 99 },
"total_revenue": { "value": 4850000 },
"product_count": { "value": 3880 }
}
Bucket Aggregation: terms
Groups documents by a field's unique values — like a GROUP BY in SQL.
GET /products/_search
{
"size": 0,
"aggs": {
"by_category": {
"terms": {
"field": "category",
"size": 10
}
}
}
}
"buckets": [
{ "key": "electronics", "doc_count": 420 },
{ "key": "clothing", "doc_count": 310 },
{ "key": "books", "doc_count": 198 }
]
Bucket Aggregation: range
Groups products into price bands — like a price filter on a shopping site:
GET /products/_search
{
"size": 0,
"aggs": {
"price_ranges": {
"range": {
"field": "price",
"ranges": [
{ "key": "Budget", "to": 1000 },
{ "key": "Mid", "from": 1000, "to": 5000 },
{ "key": "Premium", "from": 5000 }
]
}
}
}
}
"buckets": [
{ "key": "Budget", "doc_count": 240 },
{ "key": "Mid", "doc_count": 580 },
{ "key": "Premium", "doc_count": 92 }
]
Bucket Aggregation: date_histogram
Groups documents by time intervals — one bucket per month, week, or day.
GET /orders/_search
{
"size": 0,
"aggs": {
"orders_per_month": {
"date_histogram": {
"field": "order_date",
"calendar_interval": "month"
}
}
}
}
Monthly order trend (diagram): Jan ██████ 60 Feb ████████ 80 Mar ████████████ 120 Apr ██████████ 100
Nested Aggregations — Combining Bucket and Metric
Run a metric aggregation inside each bucket to get stats per group — like average price per category:
GET /products/_search
{
"size": 0,
"aggs": {
"by_category": {
"terms": { "field": "category" },
"aggs": {
"avg_price": { "avg": { "field": "price" } }
}
}
}
}
"buckets": [
{
"key": "electronics",
"doc_count": 420,
"avg_price": { "value": 8450.00 }
},
{
"key": "books",
"doc_count": 198,
"avg_price": { "value": 349.50 }
}
]
Combining Search and Aggregation
Run a query and aggregation together in one request. The aggregation applies only to the documents matching the query:
GET /products/_search
{
"query": {
"term": { "in_stock": true }
},
"size": 0,
"aggs": {
"avg_price_in_stock": {
"avg": { "field": "price" }
}
}
}
This returns the average price of only in-stock products — not everything in the index.
stats Aggregation — All Metrics in One Shot
"stats": { "field": "price" }
Response:
{
"count": 3880,
"min": 99,
"max": 85000,
"avg": 1249.5,
"sum": 4849860
}
One query returns count, min, max, average, and sum simultaneously — saves multiple round trips.
