Design a Search Autocomplete System
1. Problem Statement & Scope Clarification
System Mission
Design a real-time, globally distributed search autocomplete (typeahead) platform (similar to Google Search and Amazon product search autocomplete) capable of returning the Top-5 most relevant, high-frequency query completions as a user types into a search box, achieving sub-10 millisecond global read latency at a scale of billions of searches per day.
Functional Requirements
- Real-Time Prefix Autocomplete: Given a prefix string (e.g.,
"sys"), return the Top-5 highest-ranked completed search queries matching that prefix within . - Relevance & Popularity Ranking: Suggestions are dynamically scored and sorted based on historical query frequency, recency, geographic locality, and personalized user context.
- Real-Time Trending Ingestion: Sudden viral breaking news or high-velocity searches (e.g., breaking disaster, product launch) must surface in autocomplete within 5 minutes without waiting for nightly batch recalculation.
- Fuzzy Prefix & Typo Fallback: If a user types a misspelling or an unknown prefix that yields zero hits in the precomputed Trie (e.g.,
"sytem des"), seamlessly fall back to an approximate fuzzy search engine. - Harmful Content Filtering & Blacklisting: Prohibit offensive, hateful, or legally restricted search terms using sub-millisecond in-memory Bloom filters and dynamic remote blacklists.
- Unicode & Normalization: Support case-insensitive, accent-insensitive, and multi-byte UTF-8 character string matching across international locales.
Non-Functional Requirements (SLAs & SLOs)
- Latency: , global read latency. The autocomplete suggestions must render before the user types the next character (average human inter-keystroke interval ).
- Availability: ("five nines") uptime SLA for the online query path.
- Throughput & Scale: Support searches per day, translating to autocomplete keystroke requests daily, with peak query traffic reaching .
- Data Freshness: Offline batch Trie compilation completed weekly/nightly; streaming trending velocity merged within .
2. Capacity & Scale Estimation (Back-of-the-Envelope Math)
Traffic & Keystroke Volume
- Daily Searches Initiated: (1 Billion searches).
- Average Keystrokes per Search Session: A typical user types 4–6 characters before clicking a suggestion or pressing enter. We assume per completed search session.
- Total Daily Autocomplete Keystrokes:
- Average Read QPS:
- Peak Read QPS ( diurnal peak multiplier):
Trie Memory Footprint Estimation
- Total Unique Search Queries Retained: We retain the top () most frequent queries across a 30-day rolling window (any query searched fewer than 50 times in the window is pruned, see Section 8.2).
- Average Query Length: ( in UTF-8).
- Precomputed Top-5 Radix Node Memory Layout:
- To achieve prefix lookups, every intermediate prefix node stores its Top-5 completed suggestions directly.
- Suggestion record: 5 suggestions .
- Structural Radix node overhead (compact double-array or LOUDS tree pointer): .
- String pool storage: .
- Total per prefix node .
- Assuming an optimized Radix tree produces prefix nodes for phrases:
- ElastiCache Redis Cluster Sizing:
- Hosting the precomputed Top-5 Radix key-value lookup in an Amazon ElastiCache Redis Cluster:
- With Redis jemalloc allocator overhead () and primary + replica pairing ():
- A modest 3-node cluster of
cache.r6g.xlargeinstances ( each, total) delivers ample headroom, , and sub-millisecond memory fetches.
Network Bandwidth Sizing
- Average Autocomplete Response Size: JSON payload with 5 suggestions .
- Peak Egress Network Bandwidth:
- Edge Cache Offload: Caching top 1-3 letter prefixes at CloudFront edge PoPs offloads up to of global queries:
3. Dual-Path Architecture & AWS Component Mapping
The system utilizes a Dual-Path Architecture: an ultra-low latency Online Query Path delivering sub- suggestions, and an Asynchronous Big Data Pipeline performing streaming velocity updates and weekly batch Trie compilation.
Synthesizing vector architecture diagram...
Precomputed Top-K Materialization Eliminates Traversals Dynamic DFS traversal across Trie child nodes requires traversing all descendant suffixes and sorting candidates by score at runtime (). By materializing the precomputed Top-5 suggestions directly into each prefix key during offline compilation, queries reduce to a constant-time flat key-value lookup in ElastiCache Redis.
Data Flow Walkthrough
- Edge Interception: Keystrokes pass through CloudFront. Short 1-3 character prefixes (e.g.,
"a","am","ama") that represent over of all volume hit edge cache with round-trip times. - In-Memory Cache Lookup: Cache misses route to the Typeahead Fleet on ECS. The query service issues two parallel asynchronous queries:
- Fetches the precomputed baseline Top-5 completions from ElastiCache Redis (
trie:en:us:<prefix>). - Checks the Redis Fast Ring Buffer for any viral breaking queries matching the prefix.
- Fetches the precomputed baseline Top-5 completions from ElastiCache Redis (
- Fuzzy Fallback Execution: If the Redis Trie returns zero matches (due to a typo like
"aple ihoen"), the service triggers an asynchronous circuit-breaker-protected fallback call to Amazon OpenSearch Service, querying anedge_ngramindex with a Levenshtein edit distance of . - Asynchronous Telemetry Ingestion: Every keystroke session event is emitted via UDP/fire-and-forget buffer to Amazon Kinesis. Flink aggregates queries over a 10-minute sliding window. Sudden spikes ( standard deviation above moving baseline) are pushed to the Redis Fast Ring Buffer within minutes.
Concrete Step-by-Step Request Walkthrough: Tracing an Autocomplete Keystroke
| Step # | Event / Action | Component State | Distributed Transition | Output / Response |
|---|---|---|---|---|
| 1 | User types "sys" into search UI(Debounce timer expires at ) | Browser AbortController cancelsprevious in-flight "sy" request | Client issues GET /v1/search/autocomplete?q=sysover multiplexed HTTP/2 | Request terminates at nearest CloudFront Edge PoP |
| 2 | CloudFront Edge evaluation | Checks edge memory/SSD cache for normalized prefix q=sys | Edge cache miss: forwards payload over AWS fiber backbone to regional NLB & Envoy Gateway | Envoy validates rate limit ( per IP token bucket) |
| 3 | Typeahead Query Service execution | ECS worker evaluates in-memory Bloom filter safety blocklist | Normalized word "sys" confirmed clean;evaluates local SingleFlight mutex | SingleFlight groups identical concurrent prefixes; worker dispatches to Redis |
| 4 | Redis parallel query execution | Queries trie:en:us:sys in ElastiCache;checks trending:en:us:10m ZSET | Key found in cache; deserializes 5 binary FlatBuffer suggestion records in | Real-time trending buffer evaluated for dynamic velocity boosts |
| 5 | Dynamic score interleaving & ranking | Interleaves baseline score () with trending velocity () | Re-ranks candidates; merges localized history; evaluates tenant personalization filters | Final Top-5 list assembled in total server processing time |
| 6 | Client delivery & edge caching | Piped through CloudFront withCache-Control: public, max-age=60 | CloudFront caches response at edge; streams JSON completion list to browser | UI renders drop-down suggestions in total round-trip |
4. API Interface Design & Wire Protocol
Typeahead RESTful Query Contract
httpGET /v1/search/autocomplete?q=system+des&limit=5&country=US&lang=en HTTP/2 Host: autocomplete.production.aws.internal User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) Accept: application/json X-Client-Request-Id: req_984b2c18-4720-4e3a-921a-64119d883b1a Response: 200 OK Content-Type: application/json; charset=utf-8 Cache-Control: public, max-age=60, stale-while-revalidate=30 Server-Timing: edge;dur=1.2, redis;dur=0.6, total;dur=2.1 { "prefix": "system des", "normalized_prefix": "system des", "source": "TRIE_PRECOMPUTED", "suggestions": [ { "query": "system design interview", "score": 98500, "category": "Education", "highlight": "system des<b>ign interview</b>", "type": "HISTORICAL_POPULAR" }, { "query": "system design roadmap", "score": 84200, "category": "Career", "highlight": "system des<b>ign roadmap</b>", "type": "HISTORICAL_POPULAR" }, { "query": "system design cheat sheet", "score": 79100, "category": "Education", "highlight": "system des<b>ign cheat sheet</b>", "type": "HISTORICAL_POPULAR" }, { "query": "system description example", "score": 41200, "category": "Engineering", "highlight": "system des<b>cription example</b>", "type": "HISTORICAL_POPULAR" }, { "query": "system design primer github", "score": 38900, "category": "Software", "highlight": "system des<b>ign primer github</b>", "type": "HISTORICAL_POPULAR" } ] }
OpenSearch Fuzzy Fallback Query (When Trie Misses)
json{ "query": { "bool": { "must": [ { "match": { "query_text": { "query": "sytem des", "fuzziness": "AUTO:3,6", "prefix_length": 2, "max_expansions": 10 } } } ], "filter": [ { "term": { "status": "APPROVED" } }, { "term": { "locale": "en_US" } } ] } }, "sort": [ { "search_frequency_30d": { "order": "desc" } } ], "size": 5 }
5. Data Models & Storage Architecture
1. Redis Key Layout & Compact Binary Serialization
To maximize CPU L1/L2 cache locality and minimize memory overhead in ElastiCache Redis, precomputed suggestions are serialized using FlatBuffers into raw byte arrays:
-
Redis Key Pattern:
trie:<locale>:<prefix_string>(e.g.trie:en-us:sys) -
Redis Data Type:
STRING(Raw binary blob containing 5 serialized suggestion entries). -
Binary Payload Structure (per key, 62 bytes total: ):
Section, in byte order Size Contents Header 8 bytes Count (1 byte), then reserved bytes 5 suggestion slots 10 bytes each, 50 bytes in total QueryID (4 bytes), Score (4 bytes), Flags (2 bytes) Checksum 4 bytes CRC32C The value stores only 32-bit QueryIDs, never the query text. Each Typeahead task loads the query string table (Section 2) from the same S3 snapshot into process memory at boot, so resolving an ID to its text is an in-process array index, not a second Redis round trip. This is what keeps the Redis footprint at the computed in Section 2 instead of duplicating 20-byte strings into 200M keys. -
Real-Time Trending Ring Buffer:
- Redis Key:
trending:<locale>:10m - Redis Data Type:
ZSET(Sorted Set) - Score: Velocity metric ()
- Member: UTF-8 Query string
- Redis Key:
2. Amazon OpenSearch Index Mapping (autocomplete-catalog-v1)
Used as the secondary fuzzy fallback tier when Trie prefix matching yields zero results:
json{ "settings": { "number_of_shards": 6, "number_of_replicas": 2, "analysis": { "analyzer": { "autocomplete_analyzer": { "type": "custom", "tokenizer": "standard", "filter": ["lowercase", "asciifolding", "edge_ngram_filter"] } }, "filter": { "edge_ngram_filter": { "type": "edge_ngram", "min_gram": 2, "max_gram": 20 } } } }, "mappings": { "properties": { "query_text": { "type": "text", "analyzer": "autocomplete_analyzer", "search_analyzer": "standard" }, "canonical_phrase": { "type": "keyword" }, "search_frequency_30d": { "type": "long" }, "category": { "type": "keyword" }, "locale": { "type": "keyword" }, "status": { "type": "keyword" } } } }
Unlock Complete Architecture & Production Runbooks
You have explored the free architectural preview (~37%). Spend 1 Coin to unlock the remaining 6 production deep-dive sections for a full 24 hours.