Start with the scoring population
Take the rare term quasar. Shard A stores 100 documents and contains the term in 2. Shard B stores 100,000 documents and contains it in 2. BM25's rarity component, inverse document frequency, depends on document counts and term frequencies. Under a search mode using shard-local statistics, the same term receives a different scarcity weight on A and B. The scores coming back from those shards are not necessarily based on the same corpus-wide assumptions.
Elasticsearch commonly uses query_then_fetch, whose scoring can use local shard statistics. It also supports dfs_query_then_fetch, which performs an extra distributed frequency collection step before scoring. The latter can reduce differences caused by shard-local term statistics but costs additional work and a network round trip. It is not automatically the right default for every query. Measure whether the difference matters.
Now distinguish query and fetch phases. Each shard evaluates the query over its local search view and returns enough candidate identifiers, scores and sort information for the requested page. The coordinator merges those local lists. Only after that does it fetch the needed stored fields or _source for winners, subject to the API and selected features. This limits fetching but retains shard fanout.
At twenty shards, asking for ten from each yields at most 200 local candidate entries before merge. That arithmetic alone isn't frightening. The costly part is that twenty shards must participate and the query completes only after enough responses arrive or the engine applies its partial-result policy. A slow shard can dominate tail latency, and broad queries may perform substantial per-shard filtering and scoring even when the response contains ten hits.
Why resharding changes ranking
Moving documents among shards can change local term statistics, segment layout and the distribution of scoring work. If ranking uses local statistics, the same query and identical documents can yield different relative scores after placement changes. Replica variations and refreshing index views can also change intermediate search state. A correct distributed design states which scoring contract is expected. Is approximate relevance acceptable? Is stability across a short session more important than perfect corpus-wide statistics?
Do not oversell global term statistics either. A global BM25 score is still only a lexical scoring model. It does not repair a poorly designed query, irrelevant products or missing candidates. The previous episode on relevance showed how to measure those faults separately.
Suppose we replace exact lexical retrieval with approximate vector search. Each shard might not return its true local top ten in vector-distance order because an approximate nearest neighbor structure explores only part of the graph or cluster. The exact top-ten proof no longer applies to missing candidates. Increasing per-shard candidate breadth or using a global reranker can improve recall, at added latency. That's a different failure mode from scoring with local BM25 statistics.
Pagination is a separate consistency problem
A shopper sees page one at 12:00:00 and page two at 12:00:03. In between, several shards refresh. A product is added ahead of the previous rank boundary and another document changes score. If the application uses from and size against each new current view, the rank positions have shifted. A document may appear twice, and another may be skipped. Deep from + size also requires collecting and sorting increasing numbers of hits from each shard, which becomes expensive.
For stable deep pagination in Elasticsearch, prefer search_after with a point-in-time search context when that behavior fits the product. Keep the query and sort criteria unchanged, use the returned sort values including a deterministic tie-breaker, pass the latest PIT ID as documented, and close the PIT after use. A PIT preserves a search view for a bounded period. PIT retention consumes resources and does not freeze business truth.
If the interface intentionally shows live trending results, a consistent snapshot across multiple pages may not be the desired product. You could refresh from page one instead. The contract must be explicit.
What would I test?
I would create a fixture with known scores and distribute it unevenly across shards. Verify the exact top-K merge proof under a shared score and tie-breaker. Then vary local document-frequency distributions to detect ranking changes. Measure query_then_fetch against DFS mode, shard p99, coordinator CPU, partial shard failures, and fetching cost. Finally, add writes between page requests and test search_after with and without PIT.
The engineering lesson is that distributed top-K correctness depends on comparable scores, genuine local candidates and a defined search snapshot. Candidate counts cannot prove correctness. A strong interview answer proves the simple case first, then identifies exactly which production assumption breaks that proof.