Aggregations and facets
Aggregations go in aggs (or aggregations) of a _search body. They are computed over the documents that match query, and they ignore post_filter, exactly as in Elasticsearch. That one rule is what makes multi-select facets possible; the pattern is below.
Bucket aggregations
Section titled “Bucket aggregations”| Aggregation | Parameters |
|---|---|
terms |
field, size, order, min_doc_count |
range |
field, ranges (each with from, to, key), keyed |
histogram |
field, interval, offset, min_doc_count, keyed, extended_bounds |
date_histogram |
field, calendar_interval or fixed_interval, format, min_doc_count, keyed |
filter |
A query |
filters |
filters (an object of named queries, or an array), other_bucket, other_bucket_key |
global |
None: all documents, ignoring query |
missing |
field: documents without a value |
Every bucket aggregation can hold sub-aggregations in its own aggs. terms buckets can be ordered by _count, by _key, or by a single-value metric sub-aggregation ({"order": {"avg_price": "desc"}}).
terms and the other bucket aggregations work on keyword, numeric, boolean and date fields. A terms aggregation on a text field is an error, with the same message Elasticsearch gives.
Metric aggregations
Section titled “Metric aggregations”min, max, avg, sum, stats, value_count and cardinality, each with a field. Floating-point results match Elasticsearch to within 1e-9.
{ "size": 0, "aggs": { "by_category": { "terms": { "field": "category", "size": 5, "order": { "avg_price": "desc" } }, "aggs": { "avg_price": { "avg": { "field": "price" } } } } }}Not supported
Section titled “Not supported”Rejected with [ferroseek] unsupported:: the aggregation types date_range, extended_stats, percentiles, percentile_ranks, top_hits, significant_terms, composite, nested, reverse_nested, sampler, weighted_avg, multi_terms, rare_terms, auto_date_histogram, adjacency_matrix, geo_bounds, scripted_metric, bucket_sort, bucket_selector, median_absolute_deviation and variable_width_histogram; aggregation meta; on terms, include, exclude, execution_hint, collect_mode and shard_min_doc_count; on metrics, script, missing, format and value_type; on histogram, order and hard_bounds.
Multi-select facets
Section titled “Multi-select facets”A listing page with facets usually wants this behaviour: choosing a brand narrows the products, but the brand facet still shows every brand (so the user can tick a second one), while the colour and price facets update to reflect the chosen brand.
In one request:
- Put the user’s text search and any fixed scope (such as the category being browsed) in
query. - Put the facet selections in
post_filter. It filters the hits but not the aggregations. - Wrap each facet’s aggregation in a
filteraggregation that applies every other facet’s selection.
This is the request the example shop sends for “jacket”, with red and blue selected and no brand or price chosen:
{ "query": { "bool": { "must": [{ "multi_match": { "query": "jacket", "fields": ["name^3", "description"], "operator": "and" } }], "filter": [] } }, "post_filter": { "bool": { "filter": [{ "terms": { "color": ["red", "blue"] } }] } }, "aggs": { "brand": { "filter": { "bool": { "filter": [{ "terms": { "color": ["red", "blue"] } }] } }, "aggs": { "values": { "terms": { "field": "brand", "size": 30 } } } }, "color": { "filter": { "match_all": {} }, "aggs": { "values": { "terms": { "field": "color", "size": 30 } } } }, "price": { "filter": { "bool": { "filter": [{ "terms": { "color": ["red", "blue"] } }] } }, "aggs": { "ranges": { "range": { "field": "price", "ranges": [ { "key": "under-25", "to": 25 }, { "key": "25-50", "from": 25, "to": 50 }, { "key": "50-100", "from": 50, "to": 100 }, { "key": "100-250", "from": 100, "to": 250 }, { "key": "250-plus", "from": 250 } ] } } } }, "category": { "filter": { "bool": { "filter": [{ "terms": { "color": ["red", "blue"] } }] } }, "aggs": { "values": { "terms": { "field": "category", "size": 30 } } } } }, "sort": [{ "_score": { "order": "desc" } }, { "sku": { "order": "asc" } }], "from": 24, "size": 24, "track_total_hits": true}(Shown in a different key order from the code, and with _source left out.) The colour facet’s filter applies no colour selection, so it keeps showing all colours that match “jacket”; the brand, price and category facets count only red and blue jackets. The function that builds it, buildListingSearch, is about 25 lines and is a reasonable starting point for your own.
Limits
Section titled “Limits”A response may contain at most 65,536 buckets across all bucket aggregations at every level (Elasticsearch’s search.max_buckets, answered with 503 too_many_buckets_exception). A range aggregation takes at most 1,024 ranges, and a request at most 256 queries across all filter and filters aggregations. See Limits and differences.