skip to content

questions

6

In a search-box autocomplete service, why does one-request-per-keystroke traffic push designs toward precomputed suggestion lists instead of ranking at request time?

level: juniorimportance: must knowfreq 62%

answer

  1. count requests per typed query
  2. the next keystroke is a deadline
  3. rank offline, look up online
  4. prefix maps to a short list
  5. short prefixes are shared

basics

~20 s

Each keystroke can send a request, so autocomplete sees several times the traffic of full search and must answer before the next key. Precomputing ranked suggestions per prefix turns each request into a cheap lookup.

solid answer

~50 s

A user typing an eight-character query can send a suggestion request on most of those keystrokes, so the autocomplete endpoint takes **several times** the request rate of the search endpoint itself. Each response is also only useful if it arrives before the next keystroke, which leaves a budget of roughly `100 ms` end to end. Ranking candidates at request time (scanning matches, scoring them, sorting) is too expensive at that rate and latency. So the work moves offline: a batch job reads query logs, scores candidate completions, and stores a short, already-ranked **top-k list per prefix**. Serving then becomes a bounded lookup of `prefix -> list`, and because short prefixes are shared by many users, those lists are also highly cacheable. The price is freshness and flexibility, which a trending overlay and a small request-time rerank can partly buy back.

go deeper

for a junior

Recall that each keystroke can be a request and that the answer must arrive before the next key. Then state the fix: rank offline, store a top-k list per prefix, look it up at request time.

for a middle

Explain why request-time ranking is worst for the shortest prefixes, since they match the most candidates and are requested most often, and how a precomputed list makes cost depend on prefix length and k instead.

for a senior

Show you can estimate the traffic multiplier with stated assumptions, and name what precomputation costs in production: stale suggestions, weak personalization, and memory growth with k.

for a principal

Frame precomputation as moving cost from the hot path to a build pipeline, and discuss how much request-time reranking to allow before the latency and cacheability benefits erode.

## What an autocomplete service serves **Autocomplete** (also called **typeahead**) is the dropdown of suggested queries that appears under a search box while the user types. Each suggestion is a whole query the system believes the user probably means, such as `running shoes` for the typed text `run`. The typed text is the **prefix**; the suggestions are **completions** of it. The server side of this feature has an unusual shape compared with ordinary search: - the input is tiny (a few characters), - the output is tiny (usually 5-10 strings), - but the request rate is very high and the latency budget is very tight. ## Why the load is extreme Full search runs once per submitted query. Autocomplete can run once per **keystroke**. An illustrative estimate, with the assumptions stated: 1. Assume a site peaks at **5,000 submitted searches per second**. 2. Assume the average query is 8 characters long, and the client, after its own throttling, sends a suggestion request on about **5** of those keystrokes. 3. Suggestion traffic is then about 5,000 x 5 = **25,000 requests per second** - five times the search load, for a feature that returns ten short strings. On top of the rate, each answer has a deadline. If the suggestions for `ru` arrive after the user has already typed `run`, they are useless. Interactive-feel guidance puts that budget near **100 ms** end to end, and the network round trip consumes a large part of it before the server even starts work. ## Precompute instead of compute There are two broad ways to produce the list for a prefix: | Approach | Work per request | Freshness | Flexibility | |---|---|---|---| | **Rank at request time** | find all matching candidates, score each, sort, cut to k | immediate | high: filters, personalization, any scoring | | **Precomputed top-k per prefix** | one lookup of an already-sorted short list | as fresh as the last build or refresh | lower: ranking fixed at build time | Ranking at request time means the cost grows with the number of candidates under the prefix. A one-letter prefix can match millions of past queries, so the shortest prefixes - which are also the most frequently requested - would be the most expensive. That is the worst possible combination. Precomputation flips it. An offline **batch job** reads the query logs, counts how often each query was issued (often with a time decay so old popularity fades), and for every prefix stores the best **k** completions in order. At serving time the work is: 1. locate the entry for the prefix (a walk down a **trie**, or a key lookup in a prefix-to-list map); 2. return the stored list, optionally after a light filter or rerank over those few items. The cost now depends on the prefix length and on k, not on how many queries share the prefix. ## Side benefits of precomputation - **Cacheability.** The set of short prefixes is small (26 + 676 + 17,576 = 18,278 strings of one to three lowercase Latin letters), and most typed queries pass through them, so their lists can be cached close to users. - **Predictable latency.** Every request does roughly the same amount of work, which keeps tail latency flat. - **Offline quality control.** Unsafe or low-quality suggestions can be removed during the build, before anyone sees them. ## What precomputing gives up Precomputation is a trade, not a free win: - **Freshness.** A term that becomes popular this morning is missing until the next build, which is why production designs add a **trending refresh** path. - **Personalization and filters.** A single global list per prefix cannot reflect one user's history or a selected category. A common compromise is to precompute a slightly longer list (say 20 items when 8 are shown) and rerank or filter those few at request time. - **Storage.** Every stored prefix carries its own list, so memory grows with the number of prefixes times k. ## Summary Per-keystroke traffic multiplies the request rate, and the next keystroke sets a hard deadline. Moving the ranking offline and serving a stored top-k list per prefix makes each request cheap and uniform, at the cost of freshness and flexibility that the rest of the design then has to recover.

  • What does a precomputed suggestion list give up compared with ranking at request time?
    Freshness, because new terms appear only after the next build or a trending refresh; flexibility, because one global list per prefix cannot reflect a user's history or an active filter; and memory, because each prefix stores its own list. Designs recover some of this by storing a slightly longer list and reranking those few items per request, plus a small overlay for trending terms.
  • Why store more suggestions per prefix than the dropdown shows?
    Request-time steps such as removing a suggestion that is blocked for a region, or reranking by a user signal, discard or reorder items. If exactly the displayed number were stored, any removal would leave the dropdown short. Storing, for example, 20 for an 8-item dropdown leaves headroom, and memory grows only linearly with that k.

A coffee shop that pre-brews its three best-selling drinks before the morning rush can hand them over instantly, while made-to-order drinks would stall the queue. The trade-off is that a drink nobody expected is not ready.

saying these in an interview costs you the question

  • Autocomplete load equals search load, since it is one request per query.
  • Running the full search query on every keystroke is fine at scale.
  • Precomputing means storing every string a user could possibly type.
  • Short prefixes are cheap to rank at request time because they are short.
  • Precomputed suggestions cannot be refreshed until a full daily rebuild.
open as a page

For server-side typeahead, how does a trie with precomputed top-k per node compare with an edge-ngram index and an FST?

level: middleimportance: must knowfreq 55%

basics

~20 s

A top-k trie gives lookups proportional to prefix length but costs memory; an edge-ngram index reuses search infrastructure and ranks at query time, costing index size and latency; an FST is compact and fast but immutable, rebuilt offline.

open as a page

In a typeahead service with a sub-100 ms budget, why does caching results for short prefixes pay off so well?

level: middleimportance: should knowfreq 48%

basics

~20 s

Short prefixes are few, most typed queries pass through them, and their suggestion lists change slowly, so a small cache near users gets a high hit rate and removes both server work and much of the network round trip.

open as a page

When a typeahead suggestion structure outgrows one machine, how do you choose between hash-sharding a prefix-to-list map and range-sharding a trie by prefix?

level: principalimportance: should knowfreq 30%

basics

~20 s

Hash-sharding a flattened prefix-to-list map spreads load evenly and routes each lookup to one shard but blocks traversal features like fuzzy matching; range-sharding a trie keeps traversal but needs load-based split points and special handling for short prefixes.

open as a page

In a search-box typeahead, how can suggestions tolerate a typo in the typed prefix without breaking the latency budget?

level: seniorimportance: nice to knowfreq 30%

basics

~20 s

Allow a small, length-dependent edit distance, walk the suggestion structure with an automaton that prunes branches exceeding it, rank exact matches above fuzzy ones, and cap the work, often using fuzzy matching only when exact results are too few.

open as a page