Reference

Multi-vector retrieval

Behavior

Approach

What the current measurements suggest

BM25

Strong lexical baseline on SciFact: nDCG@10 0.663, Recall@100 0.883

Learned sparse

Similar recall with TF-IDF weights (0.888). The caller’s weight producer determines quality

Dense flat

Exact ranking reference for a chosen encoder

HNSW

0.439 top-10 overlap with exact search. Increase search breadth when recall matters

IVF-PQ

0.256 overlap at this compression. Useful for memory savings

MUVERA + MaxSim

0.341 overlap. Candidate budget and token embeddings need tuning

Rank fusion

A weak dense arm lowered nDCG@10 from 0.663 to 0.414. Evaluate each arm

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

100: hematopoietic stem-cell chromosome segregation

4381486

1

4381486, 4398832, 2547636, 15728433, 25516011

1099: statins and blood cholesterol

7662206

3

21557614, 22420524, 7662206, 7454794, 9617381

1179: the central domain of MDA5

31272411

10

10627801, 1569031, 16058322, 2566674, 52095986, additional IDs

1: inductive properties of zero-dimensional biomaterials

31715818

>100

43385013, 10608397, 40212412, 10931595, 27049238

For query 1, approximate search also changes the candidate set:

Index

First five document IDs

Exact top-10 overlap

Dense flat

1263446, 10670430, 11674596, 10365787, 11369420

10 / 10

HNSW

10365787, 10009203, 11484808, 10190778, 10518721

2 / 10

IVF-PQ

11862753, 11822354, 11090688, 10534299, 12486491

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

retrieve.py
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.

Search exact revisions through the generic index boundary
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

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.

indexes.py
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.

Explain and incrementally replace one lexical unit
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

term_frequency

Matches emitted by the injected analyzer in this unit

inverse_document_frequency

Corpus rarity at this immutable snapshot

score

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.

Search immutable artifact revisions directly
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

compose_retrieval.py
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