Typeahead / Search Autocomplete
Design a real-time search autocomplete system that returns the top suggestions as the user types, like Google Search suggestions.
These designs are for learning purposes and may not be 100% accurate or production-ready. Always cross-reference with official docs and other resources. Report an issue if you spot something wrong.
Reference Documents
Design a Web Crawler — System Design Primer
Open-source system design reference covering search autocomplete, trie-based approaches, and prefix indexing.
ArticleTypeahead Search System Design — YouTube
Video explanations of typeahead architecture, trie structures, and ranking strategies.
VideoByteByteGo — System Design Newsletter
Alex Xu's newsletter on distributed systems including search autocomplete, trie data structures, and prefix caching.
BlogOverview
What is Typeahead Search?
As a user types a query, the system returns the top-k most likely completions in real time (< 100ms). Used in Google Search, YouTube, Amazon product search.
Key operations:
- Suggest: Given prefix, return top-k completions ranked by popularity
- Log: Record actual search queries for future ranking
- Update: Periodically rebuild trie from query logs
Requirements
Functional
- Return top 5 suggestions for any prefix
- Suggestions ranked by search frequency
- Update suggestions based on recent trends (within 24h)
- Support 100+ languages (optional)
Non-Functional
- Latency: < 100ms end-to-end
- Scale: 10M queries/sec (Google scale)
- Availability: 99.99%
Capacity
- 10M queries/sec × average 5 keystrokes per query = 50M requests/sec
- Trie for top 1M terms: ~100MB in memory per server
- CDN caches top 10K prefixes — covers ~80% of traffic
Design Intuition
Data Structure: Trie
A trie (prefix tree) stores strings character by character. Each node represents a character, and each leaf (or marked node) represents a complete term.
Prefix lookup in O(p) where p = prefix length. At each node, store top-k terms for that prefix (pre-computed).
Two separate concerns
- Serving (hot path): Prefix → top-k suggestions. Must be < 100ms. Use in-memory trie or Redis.
- Building (cold path): Aggregate query logs → rank terms → rebuild trie. Can run hourly as a batch job.
CDN for top prefixes
Top 1,000 prefixes ("th", "wh", "ho") account for most traffic. Cache at CDN edge — zero backend hit for common prefixes.
High-Level Design
Serving Flow
- User types "ap"
- Check CDN cache for prefix "ap" → hit? Return immediately
- CDN miss → API Gateway → Suggestion Service
- Suggestion Service looks up trie: find node at "ap" → return pre-computed top-5 terms
Trie Node
{
"prefix": "ap",
"top_suggestions": [
{ "term": "apple", "score": 9800000 },
{ "term": "app", "score": 7200000 },
{ "term": "apply", "score": 3100000 }
]
}
Trie Update Pipeline
- Search queries logged to Query Log DB
- Batch job (hourly): count term frequencies over 7-day window
- For each trie node, compute top-k children
- Serialize updated trie → publish to Redis / push to servers
Deep Dive
Trie vs Ternary Search Tree vs Redis
- Trie in memory: fastest (O(p)), ~100MB for 1M terms
- Redis Sorted Sets:
ZRANGEBYLEXfor prefix search. Simple ops, slight overhead vs pure trie - Elasticsearch: overkill for pure prefix; good if you need fuzzy match
Personalization
Blend global frequency with per-user query history:
final_score = 0.7 × global_freq + 0.3 × user_affinity_score
Trending Terms
Recent spike in "earthquake" should surface quickly. Use a sliding 1-hour window with higher weight than the 7-day average.
Trade-offs
| Decision | Option A | Option B | Chosen |
|---|---|---|---|
| Data structure | In-memory trie | Redis sorted set | In-memory trie — fastest |
| Update frequency | Real-time | Hourly batch | Hourly batch — simpler, acceptable lag |
| Personalization | Global only | Global + user history | Global only (simpler MVP) |
| CDN caching | None | Top K prefixes | CDN — eliminates most backend hits |
Interview Tips
What Interviewers Look For
- Trie explanation — clearly explain prefix lookup and pre-computed top-k at each node
- Separate read/write paths — serving (real-time) vs building (batch)
- CDN caching — top prefixes cached at edge
- Ranking — not just alphabetical, frequency-weighted
- Update freshness — how quickly do trending terms appear?
Common Mistakes
- Linear scan through all terms for each prefix
- Not storing top-k at each trie node (recomputing every time)
- Forgetting about CDN for high-traffic prefixes