Faceted Search & Aggregations
Also Known As
facets
aggregations
filters
faceted navigation
TL;DR
Dynamically computed counts for filter categories based on current results — the 'Brand (42) | Price $0-50 (18)' sidebar that refines search results.
Explanation
Faceted search computes the count of matching documents per category value as part of the search query, using the same filters applied to the main results. Elasticsearch aggregations, Meilisearch facets, and Typesense facets handle this natively. The SQL equivalent (multiple GROUP BY queries per facet dimension) is too slow. Facets enable exploratory search — users narrow results by clicking filter values whose counts show relevance.
Diagram
flowchart LR
RESULTS[Search results] --> FACETS[Facets - filter counts]
subgraph Facet Types
TERMS[Term facets<br/>category: PHP 42<br/>category: Security 38]
RANGE[Range facets<br/>difficulty: beginner 150<br/>difficulty: advanced 80]
DATE[Date histogram<br/>updated: this month 45]
end
USER[User selects PHP] --> FILTER[Filter: category=php]
FILTER --> REFINED[Refined results + updated counts]
INFO[Counts update dynamically<br/>based on current selection<br/>Elasticsearch aggregations]
style FACETS fill:#1f6feb,color:#fff
style REFINED fill:#238636,color:#fff
style INFO fill:#d29922,color:#fff
Common Misconception
✗ Faceted search requires multiple database queries — search engines compute all facet counts in a single query; doing it in SQL with multiple GROUP BY queries is N times slower.
Why It Matters
Faceted search dramatically improves discoverability — showing 'no results' for a filter vs showing the count before clicking prevents dead-end searches.
Common Mistakes
- Computing facet counts with separate SQL GROUP BY queries — O(n) queries for n facets; use a search engine.
- Not filtering facet counts by other selected filters — the facets should reflect the current filtered result set.
- Facet values not sorted by count — users expect most common values first.
- No 'show more' for facets with many values — showing all 500 brand values overwhelms users.
Code Examples
✗ Vulnerable
// Multiple SQL GROUP BY — O(n) queries, slow:
$results = $db->query('SELECT * FROM products WHERE category = ?', [$category]);
// Separate query per facet dimension:
$brandCounts = $db->query('SELECT brand, COUNT(*) FROM products WHERE category = ? GROUP BY brand', [$category]);
$priceCounts = $db->query('SELECT price_range, COUNT(*) FROM products ...');
// 5 facets = 6 queries — gets slower as facets are added
✓ Fixed
// Elasticsearch — one query returns results + all facet counts:
$query = [
'query' => ['term' => ['category' => $category]],
'aggs' => [
'brands' => ['terms' => ['field' => 'brand.keyword', 'size' => 10]],
'price_ranges' => ['range' => ['field' => 'price', 'ranges' => [
['to' => 50], ['from' => 50, 'to' => 100], ['from' => 100]
]]],
]
];
// Single query: 1000 results + brand counts + price range counts
References
Tags
🤝 Adopt this term
£79/year · your link shown here
Added
15 Mar 2026
Edited
22 Mar 2026
Views
27
🤖 AI Guestbook educational data only
|
|
Last 30 days
Agents 0
No pings yet today
Amazonbot 7
Perplexity 6
Unknown AI 2
Ahrefs 2
Majestic 1
Google 1
SEMrush 1
Also referenced
How they use it
crawler 19
crawler_json 1
Related categories
⚡
DEV INTEL
Tools & Severity
🟡 Medium
⚙ Fix effort: High
⚡ Quick Fix
Build facets from aggregations on filtered results — each facet shows counts for the current filtered view, not the total index, so users understand exactly what's available within their current selection
📦 Applies To
any
web
api
🔗 Prerequisites
🔍 Detection Hints
Filter without dynamic facet counts; facets showing total counts not filtered counts; O(n) PHP loop to compute facet counts from results
Auto-detectable:
✗ No
elasticsearch
meilisearch
algolia
⚠ Related Problems
🤖 AI Agent
Confidence: Low
False Positives: Medium
✗ Manual fix
Fix: High
Context: File
Tests: Update