Invariant — jDisc Searchers Must Remain Stateless Singletons and Defer Summary Fill

Every com.yahoo.search.Searcher in container-jdisc is instantiated once per configured search chain generation and invoked concurrently by hundreds of request threads; all per-query mutable state must reside in Query, Result, or Execution.context(), and execution.fill(result, summaryClass) must be deferred until after global top-K windowing (offset + hits).

Why It Holds (Chesterton Fence)

  1. Thread-Safety & Hot Reconfiguration: vespa/container-disc swaps component graphs atomically on config reload while in-flight requests drain on the previous generation. Instance fields mutated during search() cause cross-query data races and memory leaks.
  2. Two-Phase Scatter-Gather Bandwidth: Phase 1 search returns lightweight Hit stubs (relevance score + GlobalId + optional match-features). Calling fill() before trimming forces C++ content nodes to read and transmit compressed document summaries for hits that will be discarded (see jdisc-stateless-searcher-chain-execution).

Seductive Wrong Takeaway (CRIT-001)

  • Misconception: Reading hit.getField("body_text") right after execution.search(query) is free or already populated.
  • Falsification: Hit fields outside match-features are Unfilled after search(); calling fill() early on 1,000 scatter-gather hits amplifies content-node docsum RPC traffic by –.
  • Do-Not-Import Boundary: Use match-features in the rank profile when a container Searcher needs per-hit numeric/tensor signals prior to final fill().