Aggregations

Elasticsearch · Practical · 13 min

Faceted navigation, dashboards and log analytics are all aggregations over search results.

Aggregations summarise the documents matched by the query, in the same request. Set "size": 0 when you only need the summary, not the hits.

  • Metric aggregations compute numbers: avg, sum, min, max, stats, percentiles, cardinality (approximate distinct count using HyperLogLog++).
  • Bucket aggregations group documents: terms (top values of a keyword field), range, histogram, date_histogram (calendar_interval: "day" or fixed_interval: "5m"), filters.
  • Sub-aggregations nest inside buckets: average price per category, errors per host per hour.
  • Pipeline aggregations work on other aggregations' output: derivative, cumulative_sum, bucket_sort.

Aggregations run on doc values, the columnar on-disk structure that keyword, numeric and date fields have by default. That's why you aggregate on category (keyword) or category.keyword, not on a text field, which errors by default.

Know the approximations: terms gathers the top terms from each shard and merges them, so counts can be slightly off with many shards (doc_count_error_upper_bound reports the bound, and shard_size trades work for accuracy). cardinality is approximate with a tunable precision_threshold. For paging through every combination of buckets, use the composite aggregation instead of a huge terms size.

Facets on an e-commerce page are typically a terms aggregation per attribute, with the user's selections applied through post_filter so the facets still show other options.

Example

GET /orders/_search
{
  "size": 0,
  "query": { "range": { "placed_at": { "gte": "now-30d/d" } } },
  "aggs": {
    "per_day": {
      "date_histogram": { "field": "placed_at", "calendar_interval": "day" },
      "aggs": { "revenue": { "sum": { "field": "total" } } }
    },
    "by_status": { "terms": { "field": "status", "size": 5 } },
    "customers": { "cardinality": { "field": "customer.raw" } },
    "order_value": { "percentiles": { "field": "total", "percents": [50, 95] } }
  }
}
# "aggregations": {
#   "by_status": { "buckets": [ { "key": "paid", "doc_count": 812 }, ... ] },
#   "customers": { "value": 431 },
#   "order_value": { "values": { "50.0": 38.5, "95.0": 212.0 } }, ... }

Remember

  • Metric aggs compute values; bucket aggs group; sub-aggs nest
  • size: 0 when you only want aggregations
  • Aggregate on keyword/numeric/date fields (doc values), not text
  • terms and cardinality are approximate across shards

Watch out for

  • Running a terms aggregation with size: 100000 to list everything; use composite and page through it.

Check yourself

  1. Why does a terms aggregation on a text field like description fail by default?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations.html

Builds on

Unlocks

Nothing builds on this yet.