Skip to content

Production Data Systems Handbook / Chapter 16

Search Systems: Text, Relevance, and Retrieval Are Not Just Filters

Treat search as a derived retrieval system with explicit freshness, relevance, access-control, and rebuild guarantees.

A Good Result Can Still Be Wrong

A customer searches a marketplace for red trail shoe size 42 under $120. The first result looks excellent: the words match, the category is right, the size is available, and the price fits. But the seller was suspended forty seconds ago. The source database knows; the search index does not.

The search engine has done its distinctive job well and still produced a result the product must not honor. Retrieval asks which imperfect matches are useful and in what order. Transactional truth asks whether this seller may trade, whether this price is current, and whether this unit can be reserved now. Combining those questions in one index does not combine their guarantees.

Search is therefore a derived read model, not merely another index and not a second authority. It earns its place when users need linguistic analysis, typo tolerance, ranking, snippets, facets, or independent retrieval scale. In return, the team accepts a pipeline whose correctness has several dimensions: useful ranking, bounded freshness, prompt deletion, complete access control, and reliable reconstruction from authoritative data.

A database filter may still be the better design for a small prefix lookup or exact identifier. The boundary is crossed when the product depends on choosing and ordering plausible matches, and must test and operate that behavior as a product of its own.

A search system diagram shows a source of truth feeding change capture, transform, and a search index. User queries pass through an access-control gate, and separate arrows show freshness, delete propagation, and rebuild path.
Search should be remembered as a derived read model: useful because it ranks and retrieves, safe only when freshness, deletion, access control, and rebuild paths are explicit.

The Search Contract

Return to the trail-shoe query. Search has three jobs that ordinary database indexes do not usually combine.

First, it analyzes text. Tokenization, normalization, stemming or lemmatization, language handling, aliases, punctuation rules, stop words, and synonym expansion all change what the system considers a match. These choices are product decisions as much as technical decisions. Searching for “running shoe,” “runnng shoes,” and “sneakers” may need to reach overlapping results without pretending the words are identical in every context.

Second, it ranks. Users rarely want every match; they want the best useful result first. Ranking may use term frequency, field boosts, recency, popularity, category quality, seller quality, freshness, personalization, or explicit business rules. A result can be syntactically correct and still be bad search if it buries the item users expect, promotes unavailable content, or ranks unsafe content above allowed content.

Third, it narrows. Search often combines fuzzy retrieval with strict filters: tenant, account, permission, location, language, price, inventory, seller, document type, date range, or retention state. Those filters are not cosmetic. They are the difference between a useful result set and a data leak, a failed checkout, or a support workflow that acts on the wrong record.

The first design question is therefore not about shard count or product choice. It is: what would make this result useful, and what would make it unsafe? Until the team can name acceptable matches, unacceptable matches, freshness tolerance, deletion behavior, and permission behavior, it has only chosen a place to put tokens.

Build the Index as a Derived Read Model

A production search index needs a disciplined feed from the source of truth. In the marketplace, product, seller, inventory, price, and eligibility facts may have different owners even though one search document copies them together. Changes may arrive through an outbox, a durable log, change data capture, periodic snapshots, or a combination. A transform then builds the searchable document: normalized text, denormalized names, categories, permission markers, freshness fields, ranking signals, and metadata.

That transform is part of the data contract, not glue code. Every copied field needs an owner and a meaning. The description is copied for retrieval. Price and stock may be copied for ranking and filtering, then rechecked before the product makes a final promise. Seller status and account eligibility are authorization facts: if the index uses copies to suppress results, their propagation target must match the harm of exposing stale data. A deletion marker may exist only long enough to drive removal. These fields share a document but not a correctness policy.

The index is healthy only if it can be rebuilt from authoritative data. Mapping changes, analyzer changes, relevance experiments, document-shape changes, corrupted derived fields, and search-vendor migrations all become less frightening when the team has a repeatable rebuild path. A credible rebuild plan includes a source snapshot, incremental catch-up, validation, a traffic switch, rollback, and old-index retirement.

The dangerous design is a one-way “sync search” script with no replay, no drift monitor, and no ownership of failed updates. That design looks cheap until the first missed delete, mapping mistake, or partial backfill. If nobody can prove how the index is rebuilt, the search system has quietly become a second database with weaker guarantees and unclear authority.

Freshness, Deletion, and Permissions

Search correctness is not one number. Different fields carry different risk when stale.

A product title can often lag for minutes. A description change may tolerate a slower path. Price and inventory usually need tighter treatment because stale search creates visible disappointment or failed checkout. Seller suspension, document deletion, privacy removal, and permission revocation are stricter still. Stale search for a renamed item is annoying. Stale search exposing a private document is a security incident.

Access control has to be designed across the whole retrieval surface. Some systems index only public or tenant-scoped content. Others index permission tokens and filter at query time. Some use separate indexes by tenant or visibility class. Each design has a cost: index sprawl, update fan-out, query complexity, cache fragmentation, or a larger blast radius for mistakes.

The review must cover more than the main result list. Facets, snippets, highlights, autocomplete, “did you mean” suggestions, cached result counts, analytics logs, exports, and recommendation side channels can leak information even when the final result click is protected. If permissions change, the design must say how quickly stale permissions disappear and how the team detects propagation failure.

Deletion deserves the same severity. A delete event can be lost, delayed, transformed away, blocked behind another failed message, or applied to the wrong document id. For ordinary content this may be a correctness bug. For privacy, safety, or contractual deletion, it is an operational control. Search designs need delete-lag metrics, sampled verification, repair queues, and an emergency path for forced removal.

Relevance Needs Regression Tests

Search quality degrades quietly because the cluster can be green while the results get worse. A new field boost can bury exact matches. A synonym can broaden a query too far. A language analyzer can improve one locale and damage another. A personalization rule can make support investigations harder because two users no longer see the same result set.

Treat relevance changes like changes to production behavior. Keep a query set with expected strong results, acceptable alternate results, unacceptable results, sensitive queries, low-result queries, and edge cases. Review ranking changes against that set before shipping. Preserve examples from incidents and support tickets because they reveal the language users actually use.

The goal is not to turn relevance into a single perfect score. The goal is to make quality inspectable. A team should be able to say, “This analyzer change improves these category queries, harms these brand queries, and does not change permission-sensitive results.” Without that discipline, search becomes a series of local tweaks whose combined effect nobody owns.

Operational Realities

Search clusters have their own operating surface. Shards, replicas, segment merges, heap or memory pressure, disk watermarks, query fan-out, mapping growth, high-cardinality facets, large documents, nested fields, highlighting, wildcard queries, and expensive aggregations can all turn a pleasant user feature into an unpredictable cost center.

A query that looks small in application code may scatter across many shards, load fields the UI barely needs, compute counts for many facets, and allocate memory under peak traffic. Average latency can hide a few pathological queries that dominate resource use. Search observability should include query shape, result count, shard fan-out, timeout rate, indexing lag, delete lag, cache behavior, memory pressure, and slow queries by feature.

Mapping discipline matters. Adding fields freely increases storage, memory, and operational risk. Changing analyzers commonly requires reindexing. Letting every team add custom fields or unbounded nested structures can make one shared search cluster carry every product experiment’s cost. Search schemas need owners, compatibility rules, and a path for retirement, not only a path for addition.

Rebuild drills are the search equivalent of restore drills. The team should know how long a full rebuild takes, what source data it uses, how catch-up works, how quality is validated, and how users are protected during the process.

When Search Is the Wrong Tool

Do not add a search engine for exact lookup. If the user supplies an id, slug, email, order number, ticket number, or stable external identifier, the system usually needs a primary-key lookup, unique constraint, or ordinary index. A search system may make that lookup slower, less current, and less obviously correct.

Do not use search as the owner of strong transactional truth. Inventory reservation, permission changes, balance updates, account status, payment state, and deletion authority belong in systems that enforce the required invariants. Search may help users find the object, but the write path and final decision should return to the source of truth.

Be careful with simple prefix search. A small dataset, bounded autocomplete list, or admin-only lookup may be served well by a relational index, trigram extension, generated column, cache, or precomputed table. Search infrastructure becomes justified when ranking, linguistic analysis, faceting, typo tolerance, independent scaling, or large retrieval sets matter enough to pay for another derived store.

The rejection test is practical: if correctness requires current facts and the query is already known precisely, search is probably the wrong primary path. If usefulness depends on retrieving, ranking, and narrowing imperfect matches, search has a job worth designing.

Write the Freshness and Rebuild Plan

An approval table would make these obligations look like independent rows. They are a sequence: authority feeds the index, lag changes what users can see, and the rebuild path has to recover both data and behavior. Write the plan in that order.

Begin with the retrieval boundary. List the queries search will own and explain why ordinary indexes, exact lookup, or a small prefix index are insufficient. For the marketplace, the trail-shoe query belongs because analysis, typo tolerance, ranking, and several facets work together. Lookup by product ID and the final stock reservation do not.

Next, describe the indexed document field by field. Name the authority, transform, analyzer, ranking use, filter use, privacy class, and acceptable staleness of each copied fact. A single “indexing lag under five minutes” target is too coarse when descriptions, prices, inventory, seller suspensions, and permission revocations have different consequences.

Then make removal and authorization testable. State the maximum propagation time for product deletion, privacy removal, seller suspension, and account-permission change. Cover the entire retrieval surface—results, facets, snippets, autocomplete, counts, caches, logs, and exports—and name the alert, forced-removal path, and verification query for a missed update.

Define quality with examples. Keep representative exact names, misspellings, category queries, synonyms, ambiguous terms, low-result queries, locale cases, and prohibited results. Include unsafe wins: a suspended seller ranked first, an unavailable product presented as purchasable, or a private item contributing to a facet count. A ranking change is ready only when the team can explain what it improves, what it harms, and which safety cases remain unchanged.

Finally, rehearse reconstruction. Build a new index from an authoritative snapshot, catch up from the change stream, compare counts and sampled versions, run the relevance and authorization cases, switch traffic through a reversible alias or routing change, and retain rollback until the old index can be retired. Record how long the exercise takes and whether retention can cover the catch-up window. This is also where shard fan-out, field growth, facet cardinality, document size, memory pressure, and pathological query shapes receive owners and limits.

Follow the Result to Its Last Authority

Run the opening query through the proposed design. Show how red trail shoe size 42 under $120 is analyzed, which fields and signals affect rank, which strict filters narrow the candidates, and where account eligibility is enforced. Now suspend the top seller while the query is cached and the indexing consumer is behind. Inspect not only the result card but its snippet, facet counts, autocomplete, analytics record, and any export.

Name the first signal that reveals the lag and the exact repair action. Then change the product’s price and sell its last unit. Decide what browsing may show, what the product page must recheck, and which authority alone may reserve stock. Delete the product and prove that it disappears from every retrieval surface within the promised time.

Repeat the exercise during a full reindex. The new index must ingest a snapshot without losing later suspensions or deletes, catch up, pass the query set, and switch without turning an old copy into authority. If the team cannot perform that sequence, the index is not yet rebuildable; it is merely replaceable in theory.

Search is justified when imperfect language must become useful ordered candidates. Its boundary is equally important: current permission, final price, inventory reservation, payment state, and other invariants return to their authoritative systems before the product acts. The search path may propose the best answer. It must not grant itself the right to make the final promise.