The five stages: ingestion, indexing, query, ranking, caching
coreadvancedA search system is five stages that people usually think of as one product, and separating them is what makes the whole thing operable. Ingestion is how documents get from wherever they live — a database, an event stream, a crawl — into a form the index can accept, which is also where enrichment, normalisation and filtering happen. Indexing turns those documents into the data structures a search engine actually queries, and it is a write-heavy, batch-friendly workload with completely different scaling behaviour from anything downstream. The query service parses what a user typed into a structured query: parsing, tokenising, spelling correction, synonym expansion, and applying filters and permissions. Ranking scores the matching documents, and it is deliberately separate from matching because the two change at different speeds — matching rules change rarely, ranking is tuned constantly, sometimes daily. Caching sits in front of the query path, where it is unusually valuable because search traffic is heavily head-weighted: a small set of popular queries accounts for a large share of volume, and their results change only when documents change. Splitting the five out matters because each has a different scaling axis, a different failure mode, and a different deploy cadence — you can reindex without touching the query service, tune ranking without reindexing, and lose the ingestion pipeline for an hour while search keeps serving slightly stale results.
Think of it as
A library, taken apart. Acquisitions receives new books and strips the packaging (ingestion). Cataloguing writes the index cards and files them (indexing). The enquiry desk turns "something about Roman roads in Britain" into a search of the card catalogue (query). The librarian decides which of the forty matching books to hand over first (ranking). And the shelf of most-requested titles by the door saves the whole round trip for the questions everyone asks (caching). Each of those has a different queue, a different staffing level and a different bad day, which is exactly why a library does not put one person in charge of all five.
What we're doing: Follow one query through the read path, and one document update through the write path, and see where they meet.
- 9
- Six seconds is the index lag, and it is a design parameter rather than a bug. The next concept is entirely about what that number costs and how to keep the product honest about it.
- 21
- The permission filter is part of the query, so the engine's match count of 4,812 already reflects what this user may see. Applying permissions after ranking instead would produce pages of fewer than twenty results and would leak, through the total count, how many documents exist that the user cannot read.
- 26
- Ranking scores 200 candidates, not 4,812. Matching narrows cheaply using the index; ranking spends real computation on a bounded set — the same two-stage retrieve-then-rank shape a social feed uses.
- 33
- The two paths are joined only by the index and its version. That decoupling is what makes stage-level failure survivable: ingestion can stop entirely and every query still returns correct, slightly older results.
Why this works: The trace shows why the five stages are worth naming: they meet in exactly one place, the index. That single join is what lets you reindex without redeploying the query service, tune ranking without touching ingestion, and survive an ingestion outage with degraded freshness instead of a search outage.
Omitting the permission scope from the cache key
Wrong
Better
What you see: A user occasionally sees documents they have no access to, in search results only, and never reproducibly — because it depends on which user filled the cache entry first. Opening any of the results returns a permission error, which is how it is usually reported.
Why: A cache key must include every input that can change the value, and permission scope changes the result set more than the query text does. Omitting it makes the cache a cross-tenant leak whose likelihood rises with cache hit rate — meaning the better the cache works, the worse the breach.
- Sources — database, event stream, crawl
- leads to Ingestion
- Ingestion — enrich, normalise, filter
- leads to Indexing
- Indexing — write-heavy, batch-friendly
- leads to Index
- Index — sharded, replicated
- leads to Ranking
- Query service — parse, expand, filter by permission
- leads to Index
- Ranking — scores a bounded candidate set
- leads to Result cache
- Result cache — head-weighted traffic, keyed on every input
- leads to Query service (miss)
- leads to Results (results)
- Results
- leads to Result cache (query)
Five stages, five different operational profiles
What must be in the cache key
Remember: Five stages: ingestion (source to indexable document), indexing (write-heavy and batch-friendly), query (parse, expand, and apply permission filters as part of the query), ranking (score a bounded candidate set, tuned constantly), caching (head-weighted traffic, keyed on every input including permission scope and index version). They meet only at the index, which is what lets each fail, scale and deploy on its own — and lets an ingestion outage degrade freshness instead of taking search down.
See also: index lag reindexing and shard sizing · inverted index and ranking pipeline · search engines as specialized not primary · cache patterns · caching ranking pagination and materialization

