SD System Design In Depth
0%
design system-designsearchautocomplete

Design: autocomplete

Module 5.4: Information Retrieval & Search Engines Updated Sep 17, 2026
📄 Cheat Sheet
6: Typeahead Suggestion + Google Search Bar | Systems Design Interview Questions With Ex-Google SWE
Jordan has no life 6: Typeahead Suggestion + Google Search Bar | Systems Design Interview Questions With Ex-Google SWE Watch on YouTube ↗

Deep interview treatment of tries with precomputed top-K, sharding by prefix, offline aggregation and caching.

0:00 / --:--

The Latency SLA of Autocomplete

Search autocomplete (typeahead) displays the top 5 to 10 suggested queries as the user types each keystroke. Because humans type at ~300ms intervals, suggestions should appear within roughly 100 milliseconds of a keystroke end to end, which leaves the server-side lookup a budget well under 10 ms because network round trips dominate.

Prefix Trie with Pre-Materialized Top-K Suggestions

flowchart TD Root["Root Node"] --> S["'s' (Top: ['system', 'sql', 'spring'])"] S --> Y["'sy' (Top: ['system design', 'system requirements'])"] Y --> S2["'sys' (Top: ['system design', 'system architecture'])"] S2 --> T["'syst' (Top: ['system design'])"]

Under the Hood: Why Naive Tries Fail at Scale

In a textbook Trie, finding matching prefixes requires traversing down to the prefix node and performing a Depth-First Search (DFS) across all descendant nodes to find the highest-frequency suggestions. In a dictionary with 100,000,000 query logs, this DFS takes hundreds of milliseconds.

The Pre-Materialization Pattern: Each Trie node pre-computes and caches the top 5 most popular global search phrases in its node payload. Querying autocomplete traverses the analyzed prefix in O(|prefix|) and then returns a bounded precomputed list. Network and serving latency must be measured; the lookup is not globally constant-time.

Offline Aggregation Pipeline

Search query click logs are streamed to Kafka and aggregated hourly via Apache Flink. Flink calculates weekly query frequency, filters offensive terms, and builds a fresh immutable Trie file. The new Trie is deployed to production Redis instances or local worker memory using zero-downtime pointer swaps.

Worked example: capacity estimate

QuantityAssumptionResult
Searches per day5 billion
Suggestion requests per searchAbout 4 after client-side debouncing of 100 to 150 ms20 billion per day
Average QPS20 billion divided by 86,400about 230,000
Peak QPS2 to 3 times averageabout 500,000 to 700,000
Suggestion indexTop 10 million queries, about 50 million distinct prefixes, about 60 bytes each for key and 10 IDsabout 3 GB, fits in RAM on every server

Because the whole index fits in memory, each server can hold a full replica and scale horizontally; sharding by prefix is only needed when the index grows much larger or is personalised.

Latency: what actually matters

Users perceive suggestions as instant if they appear within roughly 100 ms of a keystroke. Server lookup is microseconds; the budget is dominated by network round trip. Tactics: serve from the nearest region or edge, cache short prefixes (one or two characters) at the CDN and in the browser, reuse a persistent HTTP/2 connection, and cancel in-flight requests when a new keystroke arrives.

Data pipeline

flowchart LR A["Search logs"] --> B["Stream or batch aggregation"] B --> C["Filter unsafe and rare queries"] C --> D["Score with frequency and recency decay"] D --> E["Build prefix to top K table"] E --> F["Publish versioned snapshot"] F --> G["Servers load and swap atomically"]

Trade-offs

ChoiceBenefitCost
Hourly rebuildSimple, consistentMisses breaking news for up to an hour
Streaming trending layerFresh suggestions within minutesNeeds a merge of trending and base lists; abuse risk
Personalised suggestionsHigher acceptance ratePer-user state, privacy obligations
Minimum frequency thresholdBlocks rare, possibly private queriesLong-tail coverage drops

Failure modes

  • Manipulation: bots repeatedly searching a phrase to push it into suggestions; count distinct users, not raw searches.
  • Stale snapshot: if a build fails, keep serving the previous version rather than an empty index.
  • Tail prefixes: prefixes with no precomputed list should return nothing quickly rather than falling back to an expensive scan.
Check yourself Question 1 of 3
Pre-materialised top-K recall
From: Under the Hood: Why Naive Tries Fail at Scale

Why does a production typeahead store a precomputed top-K suggestion list at every trie node instead of searching the subtree when a prefix arrives?

Key Takeaways

Autocomplete should feel instant, about 100 ms end to end, so the server-side lookup must take only a few milliseconds.
Trie nodes pre-cache the top 5 most frequent search terms, turning query-time subtree searches into an O(|prefix|) lookup plus a bounded list read.
Query frequency weights are aggregated offline via streaming analytics (Flink) and loaded into in-memory Trie nodes.
Was this lesson helpful? Spot an issue or have a suggestion? Let us know on GitHub.
Report an issue