Search & Autocomplete — Interview Perspective
How to structure a search system design in an interview — the opening statement, key patterns to demonstrate, freshness/thundering-herd guidance, and a full question bank across scope, indexing, ranking, autocomplete, caching, sharding, pagination and failure curveballs.
Opening Statement
The two-sentence summary that orients the entire interview in your favor.
"I would keep the transactional database as the source of truth and maintain a separate search index optimized for query performance. The index is eventually consistent with the source — for most search use cases some seconds of lag is an acceptable trade-off, though the exact acceptable window depends on the domain."
Key Patterns to Demonstrate
Patterns that, explained clearly and without overclaiming, constitute a strong senior-level answer.
Candidate generation + ranking for autocomplete
Autocomplete is prefix → candidate generation → ranking → top suggestions. A dedicated prefix structure (trie/FST) is one valid candidate-generation approach, not the only one — search-engine prefix queries, edge n-grams, and precomputed query-log suggestions are legitimate alternatives with different trade-offs.
Retrieve then rank
Retrieve a candidate set from the inverted index (fast). Rank with signals (BM25, popularity, recency, optionally personalization) on a bounded slice of that candidate set (controlled re-ranking cost). Return top-k to the user.
Indexing pipeline
Source DB → change events (CDC, application events, or batch import — CDC is common but not the only valid mechanism) → message queue → indexing pipeline → search index. Eventually consistent; pipeline failure generally means staleness, not outage, assuming the backlog is retained and recoverable.
Cache layer with a real cache key
A cache key built from normalized query, filters, sort, locale and page — not just the raw query string. TTL and hit rate are workload-dependent, not fixed constants. Full-result caching may have low reuse for personalized/highly-filtered traffic, but component-level caching can still help.
Sharding + replication, with routing awareness
Partition document space across shards (by hash, or by a routing key that reduces fan-out for queries that can supply it). Replicate for fault tolerance and read throughput — while being honest that replication improves, but doesn't guarantee, availability during a shard failure.
Answering the Freshness Question
Interviewers often ask some version of: "What if the search index is out of date?"
Strong answer: "The search index is eventually consistent, with lag driven by pipeline throughput, batching, and refresh interval — not a fixed universal number. For most product search, users tolerate a document not appearing for a few seconds after it's added. For time-critical content, I'd tighten batching and refresh intervals and accept the added pipeline/merge cost. The right freshness SLA is a domain decision, not something technically fixed."
Mentioning Thundering Herd
When the cache fails, all traffic that was being absorbed by it now hits the search index at once — the thundering herd problem. Mentioning it unprompted is a senior signal.
Request coalescing
If many concurrent requests arrive for the same query in the same window after a cache miss, collapse them into a single upstream search request and fan the one result out to all waiting callers. This prevents thundering herd without requiring a warm cache.
The spike size is workload-dependent
The multiplier is roughly 1 / (1 - hit_rate) — for an assumed 80% hit rate that's about 5x cluster-facing load, not a fixed "10x" to memorize. Framing it as derived from an assumed hit rate, rather than a hard-coded number, is the more defensible answer.
Question Bank: Likely Questions & Follow-Ups
A structured question bank organized by the area each question probes. Numbers used below are example assumptions to reason from, not memorized facts — the strong-answer direction is always to state the assumption explicitly, then reason from it.
Scope & Requirements
Design search for an e-commerce/catalog/content platform. Where do you start?
Clarify scope before designing: what fields are searchable, whether autocomplete is required, whether filters/facets are needed, whether typo tolerance matters for this domain, whether personalization is in scope, what freshness SLA is acceptable, whether pagination needs to go deep, and rough document count/QPS. Then state the source-of-truth-vs-search-index decoupling before touching any component.
- What fields are searchable? — Tests whether the candidate distinguishes analyzed text fields (title, description) from exact keyword fields (SKU, status) — this affects both indexing and query design.
- How many documents / what QPS are we designing for? — Tests whether the candidate treats scale as an assumption to state and design around, rather than skipping straight to a fixed architecture regardless of scale.
Database vs Search Index
Why not just use SQL LIKE for search?
A leading-wildcard LIKE query generally can't use a normal B-tree index efficiently, forcing a full table scan. But the stronger argument for a dedicated engine isn't that databases can't search text at all — many support full-text/trigram indexes. It's that large-scale search needs inverted indexes, relevance scoring, analyzers, typo tolerance, facets and independent scaling together. See Trade-offs & Decisions → Database vs Dedicated Search Index.
- Can PostgreSQL/MySQL full-text search be enough? — Tests whether the candidate can identify when database-native search is genuinely sufficient — smaller corpora, modest QPS, simpler relevance needs — rather than reflexively reaching for a dedicated engine.
- When would you introduce a dedicated engine? — Tests whether the candidate names concrete triggers: high search QPS competing with transactional load, need for fuzzy matching/facets, or need to scale search independently.
Why keep the source database authoritative rather than the search index?
The search index is a read-optimized derivative built for query performance, not transactional correctness — it commonly lacks the same consistency/isolation guarantees. Keeping the database authoritative means the index can be rebuilt from scratch at any time if it becomes corrupted or diverges, which is a critical safety property.
- What if the index and database disagree? — Tests awareness of reconciliation — see Failure & Scale Scenarios → Source/Index Divergence.
Inverted Index & Query Execution
What is an inverted index, and what's stored in a posting list?
A mapping from term to the list of documents containing it. A posting entry is often richer than a bare document ID — it can include term frequency, positions (for phrase search), and field information. See Architecture Deep Dive → Inverted Index & Posting Lists.
- How do multi-term queries execute? — Tests understanding of posting-list intersection/union for AND/OR semantics, and that most real systems favor OR-with-scoring over strict boolean AND.
- Why are very common terms expensive? — Tests whether the candidate identifies that a common term's posting list can be very long, and that dictionary lookup being fast doesn't mean processing that list is free.
How does phrase search work conceptually?
It requires more than an AND of the phrase's terms — it needs the terms to appear at adjacent positions within the same document and field, which is only possible if position information was captured in the posting entries at index time.
- What if position data wasn't indexed? — Tests whether the candidate recognizes phrase search is simply not possible without positional postings — it's a design decision made at index time, not something recoverable at query time.
Autocomplete
How do you serve suggestions on every keystroke?
Generate candidates via one of several mechanisms (search-engine prefix query, edge n-grams, a dedicated trie/FST, or precomputed query-log suggestions), rank them by signals like popularity/recency/locale, and control request volume with client debounce/cancellation and server-side rate limiting/caching. See Architecture Deep Dive → Autocomplete Candidate Generation.
- Trie vs search-engine prefix — which would you pick? — Tests whether the candidate treats this as a genuine trade-off (latency isolation vs operational simplicity) rather than reflexively defaulting to a trie as "the" answer.
- How do you prevent very short prefixes from exploding cost? — Tests knowledge of minimum prefix length and bounded fuzzy-match edit distance as concrete mitigations.
How do you rank autocomplete suggestions, and how do you handle a trending term?
Rank by popularity/frequency, recency/trending signals, locale/context, and optionally personalization — with abuse/spam controls on any query-log-derived popularity signal. A trending term needs hot-key handling (request coalescing, precomputed suggestions, extra replica capacity) rather than assuming normal-case ranking infrastructure absorbs it for free. See Architecture Deep Dive → Autocomplete Ranking and Failure & Scale Scenarios → Hot Query / Hot Prefix.
- How do debounce and cancellation help specifically? — Tests whether the candidate connects client-side request control to reduced server load and to correctly discarding stale in-flight responses, not just "fewer requests."
Indexing & Freshness
How do source changes reach the index — CDC vs application events?
CDC reads committed database changes with low application coupling but adds connector/broker/ordering complexity; application-emitted events carry richer domain semantics but require reliable publishing (and solving the dual-write problem). Batch/poll import is operationally simpler but has higher freshness lag. Many real systems combine a snapshot bootstrap with one of these for incremental updates. See Trade-offs & Decisions → CDC vs Application Events vs Batch Reindex.
- What if events are duplicated or arrive out of order? — Tests knowledge of idempotent upserts and source-version/sequence checking — see Architecture Deep Dive → Indexing Pipeline Correctness.
- What if retention is exceeded before the pipeline catches up? — Tests whether the candidate recognizes incremental catch-up alone becomes insufficient, and a source reconciliation or full reindex is required — see Failure & Scale Scenarios → CDC/Event Loss or Retention Gap.
How do you rebuild the entire index without downtime?
Build a new versioned index, bulk-load a source snapshot into it, catch up on changes that occurred during the rebuild, validate document counts and search quality, then atomically switch an alias to the new index — keeping the old index briefly for rollback. Never rebuild the live index destructively in place. See Architecture Deep Dive → Zero-Downtime Reindexing.
- What if the rebuild fails partway through? — Tests whether the candidate recognizes the old index keeps serving throughout, since the new index was never live — see Failure & Scale Scenarios → Reindex Failure During Migration.
Ranking
What's the BM25 baseline, conceptually?
A document scores higher the more often a query term appears in it, with diminishing returns per additional occurrence, and higher if the term is rare across the whole corpus (more distinctive) — normalized so short documents aren't penalized and long documents aren't rewarded just for length. This is a baseline lexical signal, not the final word on relevance.
- How do popularity and recency fit in on top of BM25? — Tests understanding of the staged ranking pipeline — first-stage lexical score, then optional re-ranking with additional signals on a bounded candidate set.
What happens if the ranking/re-ranking service is slow or unavailable?
Fall back to first-stage lexical (BM25-style) ranking and skip personalization/business re-ranking — preserving search availability at the cost of relevance quality, rather than failing the whole query. See Failure & Scale Scenarios → Ranking Service Failure.
- How does personalization affect caching? — Tests whether the candidate connects personalization to reduced full-result cache reuse, while recognizing component-level caching can still help.
Filters & Facets
What's the difference between a filter and a relevance-scoring clause?
A filter constrains eligibility (category, price range, in-stock) typically without contributing to the text relevance score; a scoring clause (a keyword match) determines both eligibility and ranking strength. Keeping these separate avoids bugs where a filter accidentally influences ranking, or a facet count ignores an applied filter. See Architecture Deep Dive → Filters and Facets.
- Why can high-cardinality facets be expensive? — Tests understanding that facet aggregation cost scales with the matching-set size and field cardinality — a facet over a field with thousands of distinct values (e.g. brand) on a large matching set is materially more expensive than retrieving top-k.
How do filters affect the cache key?
Every distinct filter combination is effectively a distinct query for caching purposes — a page with many filterable facets can produce a very large number of realistic combinations, which dramatically increases cache-key cardinality and can lower effective hit rate versus caching keyword-only queries.
Caching
What exactly is the cache key — why not just the query text?
Because the correct response also depends on filters, sort, locale/market, page/cursor, and ranking/model version — caching on query text alone would return wrong or stale results whenever any of those differ between two requests with the same raw text. See Architecture Deep Dive → Search Cache Design.
- Would you cache personalized search? — Tests whether the candidate avoids the absolute "never cache personalized queries" answer, and instead reasons about low full-result reuse vs viable component/segment-level caching.
What happens when the cache layer disappears — how do you prevent a stampede?
Cluster-facing load rises by roughly 1/(1-hit_rate). Request coalescing is the primary defense (collapsing identical concurrent requests into one upstream query), plus TTL jitter to avoid synchronized mass expiry, and enough capacity headroom or load shedding to survive the realistic spike size for the actual workload.
- When is caching ineffective? — Tests recognition that very high query cardinality (heavy personalization, many filter combinations) can leave little reusable structure at the full-result level, though component caches may still help.
Sharding & Replication
How do you shard the index, and why hash by document ID?
Hash sharding by document ID gives balanced distribution with a simple, predictable assignment rule — at the cost of broad queries needing to fan out to every shard, since any document could be anywhere. Routing by a meaningful key (tenant, category) can reduce fan-out for queries that can supply it, at the risk of imbalance. See Trade-offs & Decisions → Hash Sharding vs Routed/Domain Sharding.
- Can routing avoid all-shard fan-out entirely? — Tests whether the candidate recognizes this only helps for queries that can supply the routing key — a cross-tenant or cross-category query still needs broader fan-out.
Why does scatter-gather increase tail latency, and what if one shard times out?
The coordinator's response time is bounded by the slowest shard queried — more shards queried means more exposure to any single slow outlier. If a shard times out, the system must choose between failing the whole query or returning a result explicitly marked as partial. See Trade-offs & Decisions → Fail Query vs Return Partial Results and Failure & Scale Scenarios → Partial Shard Failure.
- How would you rebalance an overloaded shard? — Tests awareness that rebalancing commonly involves real data movement/recovery work, not simply a lightweight metadata change — see Failure & Scale Scenarios → Hot Shard / Uneven Distribution.
Pagination
Why is deep OFFSET pagination expensive in a distributed search system?
Each shard must compute and return results up to the requested offset, not just the page size — coordinator and per-shard work both grow with page depth. It's also not fully correct: if the underlying document set or ranking changes between page requests, offset-based paging can duplicate or skip results. See Architecture Deep Dive → Pagination and Stable Search Results.
- How does search-after/cursor pagination fix this? — Tests whether the candidate can explain carrying forward stable sort values plus a deterministic tiebreaker (commonly document ID) so each shard resumes from a position instead of recomputing from scratch.
- What if ranking changes between pages? — Tests awareness that search-after isn't automatically immune to this either, and that point-in-time/snapshot semantics exist for cases needing stronger consistency.
Failure Curveballs
The cache is down — what happens?
Cluster-facing load rises based on the actual hit rate; request coalescing and capacity headroom are the primary mitigations. See Failure & Scale Scenarios → Cache Failure / Stampede.
A shard is down — what happens?
If a healthy replica exists, it can take over with reduced capacity or elevated latency; if not, the system either fails the query or returns explicitly-marked partial results, depending on policy. See Failure & Scale Scenarios → Search Node / Shard Failure.
The indexing pipeline is 30 minutes behind — what happens?
The index keeps serving a stale-but-available view; recovery depends on retained backlog, sufficient catch-up throughput, correct ordering, and no poison event blocking progress. See Failure & Scale Scenarios → Indexing Pipeline Backlog.
A bad index deployment goes live — how do you recover?
Roll back via the alias to the last known-good versioned index rather than attempting to patch a live index in place; rebuild from the source of truth if the underlying data itself was affected. See Failure & Scale Scenarios → Bad Index Deployment / Corrupt Index.
An old update arrives after a newer one for the same document — what happens?
Without source-version checking, the delayed old update can silently overwrite the newer state. The fix is comparing incoming event version against the currently-indexed version and rejecting stale writes — including the sharper edge case of a stale update arriving after a delete/tombstone. See Failure & Scale Scenarios → Out-of-Order Index Updates.
Autocomplete suggests a term for a viral/trending query — how do you handle the load?
Hot-key cache handling (coalescing, possibly replicating the hot entry), targeted replica capacity, rate limiting, and precomputed suggestions rather than live-scoring every request for that prefix. See Failure & Scale Scenarios → Hot Query / Hot Prefix.
A user submits an expensive wildcard/fuzzy query — how do you protect the cluster?
Bound query complexity (max clauses/expansions), enforce a query deadline, apply minimum prefix length and bounded edit distance for fuzzy matching, and cap facet cardinality. See Failure & Scale Scenarios → Expensive Query / Query-of-Death.
The CDC/event history needed to catch up has been lost or exceeded retention — now what?
Incremental catch-up alone can't recover — reconcile against the source (counts/checksums/sampling) and perform a full reindex from a source snapshot, validating before cutover. See Failure & Scale Scenarios → CDC/Event Loss or Retention Gap.
A full reindex is required after a schema/analyzer change — how do you do it safely?
Build into a new versioned index, bulk-load and catch up, validate, then atomically switch the alias — never rebuild the currently-serving index destructively in place. See Architecture Deep Dive → Zero-Downtime Reindexing.
Quick reference
- Open with the source-of-truth versus search-index split, and name the freshness window for the domain.
- Retrieve then rank: bounded candidate set first, richer ranking second.
- Cache key includes query, filters, sort, locale and page; derive the cache-failure multiplier as 1 / (1 − hit rate).
- Scatter-gather: response time follows the slowest shard queried; explain hash versus routed sharding.
- Paginate deeply with search-after, not offset; reindex via a new versioned index and an alias switch.
- For failures, say what the user sees: replica takeover, marked partial results, or a clean error.