Design a Search Autocomplete System
A Senior/Staff walkthrough of a search autocomplete system that returns ranked suggestions in under 100ms at roughly 700K peak QPS, built on an in-memory compressed trie with pre-computed top-K and fed by a streaming log pipeline. The interesting tension is freshness versus latency: a 15-minute batch rebuild keeps the trie clean while a real-time fast path injects trending queries within minutes, all absorbed by a four-layer cache. Follow it top to bottom, or jump to any step.
Requirements
Functional Requirements
- Real-time suggestions: Show top 5-10 suggestions as user types each character
- Ranking: Suggestions ranked by popularity (frequency), recency, and personalization
- Multi-language support: Handle queries in any language
- Trending queries: Surface trending/breaking topics quickly
- Spell correction: Handle minor typos in prefix
Non-Functional Requirements
- Latency: < 100ms per keystroke (must feel instantaneous)
- Availability: 99.99% — autocomplete is part of core search
- Scale: 5B searches/day, each averaging 4 keystrokes = ~20B autocomplete requests/day
- Freshness: Trending queries appear within minutes; general popularity updated hourly
Constraints
- Must filter offensive/sensitive suggestions
- Privacy: don't leak other users' queries in suggestions
- Mobile vs desktop: different display constraints
Back-of-envelope estimation
API design
Key considerations:
- No authentication required (fast path, no user lookup on critical path)
- user_id is optional — used for personalization if available
- Results cached aggressively at CDN/edge
Data model
Trie (In-Memory): Primary data structure
Search Logs: Kafka → Aggregation Pipeline
Aggregation Storage: Redis (for real-time counts)
Phrase Database: PostgreSQL (source of truth for periodic trie rebuild)
High-level architecture
Data Flow: Autocomplete Request
1. User types “how t” → client debounces (50ms) then sends request
2. CDN checks cache for prefix “how t” → cache hit serves immediately
3. On cache miss, routes to Autocomplete Service
4. Service looks up “how t” in in-memory trie → returns pre-computed top-10
5. If user is logged in, overlay personalized results (recent searches, user interests)
6. Response cached at CDN with short TTL (5-15 min)
Data Flow: Trie Update Pipeline
1. Every search query logged to Kafka
2. Stream processor aggregates query counts per time window (1hr, 24hr, 7d)
3. Trending detector identifies queries with abnormal velocity (spike detection)
4. Trie Builder runs every 15 minutes:
- Reads aggregated counts from DB
- Merges trending queries with boosted scores
- Filters blocked/offensive phrases
- Builds new trie with pre-computed top-K per prefix
- Atomically swaps new trie into Autocomplete Service (blue-green)
Deep dives
WHERE STAFF IS WONDeep Dive 1: Trie Data Structure and Optimization
Basic trie stores one node per character. For 100M phrases, this is memory-intensive.
Optimization 1: Compressed trie (Patricia trie)
- Merge single-child chains: "h-o-w- -t-o" becomes a single edge "how to"
- Reduces node count by ~60%
Optimization 2: Pre-computed top-K at each node
- Store the top 10 suggestions at every trie node
- On query: O(prefix_length) lookup, no need to traverse subtree
- Tradeoff: More memory but O(1) suggestion retrieval
Optimization 3: Two-level trie
- First 2 characters → hash map (fast lookup for 676 possible bigrams)
- Remaining characters → compressed trie
- Reduces average lookup depth
Memory estimation:
- 100M phrases × 500 bytes per phrase (with top-K) ≈ 50 GB
- Fits in a single high-memory server (256 GB RAM)
- Replicated across multiple servers for availability and throughput
Alternative: Sorted array with binary search
- Store all phrases sorted, use binary search for prefix
- Less memory than trie, but slower for prefix matching
- Better for disk-based systems
Our choice: Compressed trie with pre-computed top-K, replicated across serving fleet.
Deep Dive 2: Ranking Algorithm
Scoring formula:
Components:
Trending detection (key for breaking news):
- Track query frequency in sliding windows (1hr, 6hr, 24hr)
- Compute velocity: current_window / historical_average
- If velocity > 5x, flag as trending
- Fast path: trending queries injected into trie within minutes (not waiting for periodic rebuild)
Personalization:
- User's recent searches (last 100) stored in session/cookie
- Overlay personal suggestions on top of global suggestions
- Privacy: personalization happens at query time, not stored in global trie
Deep Dive 3: Caching Strategy
Multi-layer caching is critical for 700K peak QPS at < 100ms:
Layer 1: Client-side cache
- Browser caches recent prefix results
- If user types "how t" then "how to", client can filter locally
- Reduces ~30% of requests
Layer 2: CDN edge cache
- Popular prefixes (top 10K) cached at CDN
- TTL: 5-15 minutes (balance freshness vs hit rate)
- Hit rate: ~70% of remaining requests
- Key: autocomplete:{lang}:{prefix}
Layer 3: Application-level Redis cache
- Store computed results for medium-popularity prefixes
- TTL: 1 hour
- Hit rate: ~80% of CDN misses
Layer 4: In-memory trie
- Handles remaining cache misses
- Direct memory lookup: < 1ms
Effective hit rates:
- Client: 30% → 700K × 0.7 = 490K to CDN
- CDN: 70% of 490K → 147K to app servers
- Redis: 80% of 147K → 29K to trie
- Trie handles ~29K QPS (easily manageable)
Bottlenecks & tradeoffs
Bottlenecks
1. Trie rebuild latency: Building a new trie from 100M phrases takes minutes
- Mitigation: Build in background, atomic swap; incremental updates for trending
1. Hot prefixes: “how”, “what”, “why” get massive traffic
- Mitigation: CDN caching handles this; these prefixes have very stable results
1. Long-tail prefixes: Rare prefixes have no good suggestions
- Mitigation: Fall back to fuzzy matching or spell correction
1. Offensive content: New offensive phrases can emerge quickly
- Mitigation: Real-time blocklist checked at serving time; async content moderation pipeline
Key Tradeoffs
Monitoring & Alerting
- Autocomplete latency p99 — alert if > 200ms
- CDN cache hit ratio — alert if < 60%
- Trie rebuild duration — alert if > 30 min
- Suggestion quality (click-through rate on suggestions) — track weekly
- Blocked phrase bypass rate — alert on any offensive suggestion getting through
- QPS per service instance — capacity planning
Failure Modes
- Trie server failure: Requests routed to other replicas; no impact with 3+ replicas
- CDN failure: Traffic hits app servers directly; may need to shed load
- Kafka lag (search logs): Trie becomes stale; trending queries delayed
- Redis failure: More traffic hits trie directly; slightly higher latency
- Trie rebuild failure: Keep serving old trie; alert for manual intervention
Rubric — Senior vs Staff
Want more breakdowns like this?
Join free early access for upcoming RAG, LLM eval, agents, and AI infrastructure walkthroughs.