Module 12 · Lesson 11

Design product search

An inverted index, a relevance function, and filters that must stay fast as the catalogue grows.

Advanced 7 min read Updated 2026-11-02

What you will be able to do

  • Explain inverted index and analyzer basics
  • Design faceted filtering without a full scan
  • Choose ranking signals and evaluate them
  • Keep the index consistent with the source of truth

Requirements and estimates

  • Functional: keyword search over titles, descriptions and attributes; filters by category, price, brand; sort by relevance, price or rating.
  • Non-functional: p99 under 200 ms, index freshness under 1 minute, typo tolerance.
  • Scale: 100M products, 50k queries/s peak, 5M updates/day.
100M docs x ~500 B indexed fields = ~50 GB of terms+postings
with 2x overhead and replicas: ~300 GB cluster
queries 50k/s / 20 shards = 2.5k/s per shard, feasible
updates 5M/day = ~60/s, batched into bulk refreshes

Index pipeline

Change capture
Product updates publish events from the catalog service; no direct writes to the index.
Enrich
Join category, brand, availability and rating into a search document.
Analyze
Lowercase, tokenise, apply synonyms and stemming per language field.
Bulk index
Batch writes on a short interval; an upsert keyed by product id keeps documents idempotent.
Refresh
Near-real-time refresh interval of a few seconds; rebuilding from source is always possible.
Never make the index authoritative
If the index is lost or corrupted, it must be rebuildable from the catalog database. Prices and stock shown in results should be validated at cart time, not trusted from a stale index.

Filtering and facets

Filters run on structured fields with doc values, so a category and price range narrow the candidate set before scoring. Facets are counts computed per filter dimension while the query executes — expensive if done naively for every combination, so real systems compute counts for the unfiltered dimensions selectively and cache popular queries.

  • Filter before score. Cheap structured filters reduce the documents that need text scoring.
  • Cache hot queries with a short TTL; search traffic is heavily skewed to a small set of terms.
  • Bound pagination. Deep pages (10,000 results) force large scans; cap or use search-after cursors.
  • Typo tolerance has a cost. Fuzzy matching enlarges the term set; limit edit distance and field scope.

Ranking

SignalWhy it mattersRisk
Text relevance (BM25)Query and document matchRewards keyword stuffing
Popularity / salesReflects real demandEntrenches incumbents
Conversion rateQuality proxyNoisy for new items
Price competitivenessCommercial valueCan hurt margin
Recency / availabilityRelevant and buyableNew items lack signals

Ranking is a product decision expressed as a formula. Start with BM25 times a business multiplier, then evaluate with a fixed set of judged queries. Offline metrics before online A/B, always — otherwise every tweak is an opinion.

The closing line
"Catalog events feed a bulk-indexing pipeline into a sharded search cluster; filters run on structured fields before scoring; ranking is text relevance with a business multiplier; the index is derived and can be rebuilt from the catalog."

Worth remembering

  • An inverted index maps tokens to documents; analyzers decide what a token is.
  • Facets are pre-aggregated counts per filter value, not queries per filter.
  • Ranking blends text relevance with business signals; measure with judgments, not intuition.
  • The search index is derived — always rebuildable from the database, never the source of truth.

Checkpoint

Answer all 3 questions to finish the lesson.
1. Why must the search index be rebuildable from the database?
Derived stores cannot be the source of truth. Mapping changes alone often require reindexing every document.
2. What is the purpose of applying structured filters before scoring?
Scoring is the expensive part. Removing documents that cannot match the filter reduces the work before relevance is computed.
3. Why cap deep pagination?
Offset pagination must scan and discard preceding hits, so depth multiplies work. Cursors avoid the skip cost.