Reference
Multi-vector retrieval¶
Behavior¶
Approach |
What the current measurements suggest |
|---|---|
BM25 |
Strong lexical baseline on SciFact: nDCG@10 |
Learned sparse |
Similar recall with TF-IDF weights ( |
Dense flat |
Exact ranking reference for a chosen encoder |
HNSW |
|
IVF-PQ |
|
MUVERA + MaxSim |
|
Rank fusion |
A weak dense arm lowered nDCG@10 from |
The index slice uses one fixed 128-dimensional feature-hashing encoder, making dense flat the exact ranking oracle. The approximate-index rows report measured overlap for this setup.
Actual SciFact ranking differences
Query |
Relevant document |
BM25 rank |
Top BM25 documents |
|---|---|---|---|
|
|
1 |
|
|
|
3 |
|
|
|
10 |
|
|
|
>100 |
|
For query 1, approximate search also changes the candidate set:
Index |
First five document IDs |
Exact top-10 overlap |
|---|---|---|
Dense flat |
|
10 / 10 |
HNSW |
|
2 / 10 |
IVF-PQ |
|
1 / 10 |
Mari implements MUVERA fixed-dimensional candidate generation, PolarQuant compression, and exact normalized MaxSim reranking in one retrieval path.
Query token vectors
MUVERA
Candidate documentsallowed IDs
exact MaxSim
RetrievalHit[]ranked + scored
from mari_kit.retrieval import FDEConfig, build_index, search_index
index = build_index({doc.document_id: token_vectors},
config=FDEConfig(repetitions=20, projection_dimension=16))
hits = search_index(index, query_token_vectors, limit=8,
allowed_document_ids=authorized_document_ids)
serialize_index and deserialize_index use versioned, checksummed payloads. exact_maxsim is public for direct scoring.
Authorization must precede scoring. Supply allowed_document_ids. Post-filtering can leak information through ranks and fallback behavior.
RevisionBM25Index provides the structural-reference form of the lexical
contract. It accepts RevisionRef keys and an allowed_refs set, then returns
RevisionIndexHit values. BM25Index and document-ID indexes remain available
for compatibility and lower-level use.
from mari_kit.retrieval import (
IndexOperation, RevisionBM25Index, RevisionIndexDelta,
)
index = RevisionBM25Index({document_ref: document_text})
hits = index.search(query, limit=10, allowed_refs=authorized_refs)
index = index.with_deltas([RevisionIndexDelta(
ref=current_ref,
previous_ref=prior_ref,
operation=IndexOperation.UPSERT,
text=current_text,
)])
with_deltas returns a new snapshot after exact revision-checked edits and
deletions. A stale previous_ref raises before the original snapshot changes.
Each update rebuilds BM25 statistics in time proportional to the corpus.
How it works and backing algorithms¶
Mari’s current path uses token-level late interaction: each query token takes its maximum similarity to any document token, and the maxima are averaged. MUVERA maps those multi-vector sets to fixed-dimensional encodings for fast candidate generation. Mari then reranks candidates with exact MaxSim. The packed Polar codec compresses candidate encodings at the implementation level.
Multi-vector late interaction¶
MUVERA compresses a set of token vectors into fixed-dimensional encodings for candidate search. Mari then applies exact ColBERT-style MaxSim to those candidates: each query token selects its strongest document-token cosine match and the matches are averaged. exact_maxsim(..., query_weights=...) accepts non-negative finite query weights with a positive sum and computes a weighted average. Choose this when token-level distinctions justify a larger index and a reranking stage. MUVERA · ColBERT
Dense flat search¶
Dense flat search compares the query with every passage vector. Callers can use cosine, dot product, or L2 distance. It costs a full scan and returns the exact ranking for the selected metric. Approximate-index recall uses this ranking as its reference. Dense Passage Retrieval
HNSW¶
HNSW stores vectors in layered proximity graphs. Search begins in sparse upper
layers and descends into denser neighborhoods. ef_search controls how many
candidates remain active. Higher breadth evaluates more candidates. Measure
its recall and distance calculations on the target corpus. HNSW
Authorization filters can disconnect graph paths, so small allowlists lose
recall first. exact_filter_threshold scores the authorized vectors exactly
when an allowlist is at or below that size. search_starts merges several
deterministic authorized traversals for larger allowlists. Additional starts
improve recall at additional query cost. Results remain approximate. Both
default to the original single-traversal behavior.
IVF-PQ¶
IVF first assigns vectors to coarse partitions and searches selected partitions. Product quantization stores each residual as short codebook indexes. More probes and larger codebooks improve fidelity. They increase latency and memory. Product Quantization · Faiss
BM25 and learned sparse vectors¶
BM25 scores exact term matches with term-frequency saturation and document-length normalization. Learned-sparse search uses the same inverted-index shape and accepts model-produced term weights, allowing vocabulary expansion with a caller-owned training framework. Lexical retrieval suits names, identifiers, and domain terms. Learned sparse vectors suit cases with an upstream model and measured benefit. BM25 and Beyond · SPLADE
Rank fusion¶
Reciprocal-rank fusion converts each result list to rank contributions and sums them, avoiding calibration between unrelated score scales. It works best when the arms retrieve complementary relevant material. Adding a weak or redundant arm can make the final order worse. Mari retains each arm’s contribution so that change is inspectable. RAG-Fusion
Graph propagation¶
Personalized PageRank starts probability mass at query-linked nodes, repeatedly follows allowed graph edges, and projects node scores back to passages. It can recover multi-hop context when entity links and authorization filters are reliable. HippoRAG
Index interfaces¶
The index classes expose the same authorization-aware search shape. Each class retains its algorithm-specific controls. Index selection is pipeline configuration and can be evaluated against recall, latency, memory, freshness, and ACL-filter behavior.
from mari_kit.retrieval import (
BM25Index, DenseFlatIndex, HNSWIndex, IVFPQIndex, SparseVectorIndex,
)
exact = DenseFlatIndex(vectors, metric="cosine")
graph = HNSWIndex(vectors, metric="cosine", m=32)
compressed = IVFPQIndex(vectors, partitions=256, subquantizers=16)
lexical = BM25Index(passages, k1=1.2, b=0.75)
sparse = SparseVectorIndex(model_generated_term_weights)
hits = graph.search(query_vector, limit=20, ef_search=128,
allowed_document_ids=authorized_document_ids,
exact_filter_threshold=200, search_starts=4)
BM25 accepts a caller analyzer and produces per-term score contributions.
with_deltas returns a new snapshot after revision-checked upserts and deletes,
so a streaming change can update a revisioned snapshot directly.
from mari_kit.retrieval import IndexDelta, IndexOperation
lexical = BM25Index(
passages,
analyzer=domain_analyzer,
revisions=passage_revisions,
)
why = lexical.explain("refund window", item_id="policy#returns")
lexical = lexical.with_deltas([IndexDelta(
item_id="policy#returns",
operation=IndexOperation.UPSERT,
text="Returns are accepted within 14 days.",
expected_revision="v7",
revision="v8",
)])
Explanation field |
Meaning |
|---|---|
|
Matches emitted by the injected analyzer in this unit |
|
Corpus rarity at this immutable snapshot |
|
This query term’s contribution after length normalization |
ArtifactBM25Index accepts ArtifactRef keys and returns ArtifactIndexHit
values. Multiple immutable revisions remain distinct through the typed ref
field. Use RevisionBM25Index for the shared structural-reference contract.
from mari_kit.retrieval import (
ArtifactBM25Index, ArtifactIndexDelta, IndexOperation,
)
index = ArtifactBM25Index({unit.ref: unit.text for unit in retrieval_units})
hits = index.search(query, limit=10, allowed_refs=applicable_refs)
why = index.explain(query, ref=hits[0].ref)
index = index.with_deltas([ArtifactIndexDelta(
ref=current_ref,
previous_ref=prior_ref,
operation=IndexOperation.UPSERT,
text=current_text,
)])
previous_ref is an exact optimistic revision check. Mari replaces that unit
and leaves canonical-manifest selection to the caller.
Rank fusion, graph recall, and diverse packing¶
MUVERA
lexical
recent
RRF
authorized nodes
PageRank
passage projection
MMR
Context candidatesscores and contributions retained
from mari_kit.retrieval import (
maximal_marginal_relevance, personalized_pagerank,
project_graph_scores, reciprocal_rank_fusion,
)
fused = reciprocal_rank_fusion(
{"muvera": dense_ids, "lexical": lexical_ids, "recent": recent_ids},
weights={"recent": 0.25}, rank_constant=60,
eligible=authorized_document_ids.__contains__, limit=40)
nodes = personalized_pagerank(graph, query_seeds,
allowed_node_ids=authorized_graph_nodes, damping=0.85)
passages = project_graph_scores(nodes.hits, node_passages, limit=20)
context = maximal_marginal_relevance(
{hit.document_id: hit.score for hit in fused},
similarity=passage_similarity, relevance_weight=0.65, limit=12)
assert nodes.converged