Treat the document ID as a retrieval contract

Dense and sparse indexes answer different questions. Dense retrieval can surface semantically related content, while BM25 can strongly match exact terms, identifiers, and uncommon phrases. To use both result sets safely, each indexed record should carry an ID that represents the same logical retrieval unit.

The retrieval unit might be a full document, a section, a support article chunk, or a product record. Choose that unit deliberately. If dense vectors are created per chunk but the sparse index stores only whole documents, the application cannot directly join the two result sets without an additional mapping layer.

  • Use one canonical ID format across dense and sparse indexing.
  • Encode the retrieval unit in the ID design, such as document-level or chunk-level.
  • Keep parent-document IDs separate when chunks need to roll up to a source document.
  • Avoid IDs derived from mutable titles, filenames, or array positions.

Make IDs deterministic across reindexing

An ID should remain stable when a document is reprocessed. Deterministic IDs let an indexing job identify the record it intends to replace or remove, and they prevent unchanged content from becoming a new logical document simply because it was ingested again.

A common pattern is to build an ID from a durable source-system key plus a stable chunk discriminator. For example, a knowledge-base article identifier can be combined with a section key. If chunk boundaries are regenerated from text offsets alone, small edits can shift many offsets; a semantic section key or an explicit content version may be more appropriate.

  • Start with an immutable source-system identifier whenever one exists.
  • Add a stable chunk or field discriminator for multi-vector documents.
  • Store a content version or updated timestamp as metadata rather than replacing the canonical ID.
  • Define deletion behavior for source documents and all of their child chunks.

Merge results by ID, not by rank position

At query time, dense and sparse searches may return overlapping but differently ordered candidates. Rank position is local to each retrieval method, so position one from one list is not inherently equivalent to position one from another. Use the canonical ID to detect overlap and to attach scores, source information, and metadata to a shared result record.

This structure also makes debugging clearer. An application can record whether a result was returned by dense search, BM25, or both, then inspect the underlying document metadata. Any later ranking or fusion policy should operate on this joined representation rather than on two unrelated arrays of search hits.

  • Create an application-side map keyed by canonical document or chunk ID.
  • Preserve each retrieval path's score and rank as separate fields.
  • Record which retrieval path produced each candidate.
  • Apply filters and parent-document deduplication after candidates are joined.