Accepted
Hybrid retrieval combines candidate rankings generated from heterogeneous scoring functions:
- Dense vector search scores: Cosine similarity in range
$[-1.0, 1.0]$ (typically$[0.4, 0.9]$ for relevant text). - BM25 scores: Unbounded positive floating-point numbers depending on query length and collection term frequencies (
$[0.0, 35.0+]$ ). - SPLADE sparse scores: Dot products of sparse expanded activations (
$[0.0, 50.0+]$ ).
Because score scales and distributions differ drastically between dense and sparse spaces, naive linear weighted score combinations (
-
Linear Weighted Score Combination:
- Pros: Simple.
-
Cons: Requires score normalization (e.g. Min-Max or Z-Score), which is vulnerable to extreme outlier scores; requires tuning weight
$\alpha$ ; unstable across diverse query categories.
-
Distribution-Based Score Fusion (DBSF):
- Pros: Normalizes scores based on statistical distribution per query.
-
Cons: Requires a large candidate pool (
$k > 100$ ) to compute meaningful distribution parameters; sensitive to small candidate sets.
-
Reciprocal Rank Fusion (RRF):
- Pros: Rank-based and score-invariant; robust across vastly different score distributions; does not require per-query score normalization; proven standard in IR benchmarks (Cormack et al.).
- Cons: Ignores relative margin of victory between ranks (rank 1 vs rank 2 is treated identically regardless of raw score gap).
Adopt Reciprocal Rank Fusion (RRF) executed server-side within Qdrant:
Where:
-
$M$ is the set of retrieval systems (e.g.$M = {\text{dense}, \text{bm25}}$ or$M = {\text{dense}, \text{sparse}}$ ). -
$\text{rank}_m(d)$ is document$d$ 's 1-based rank in retrieval system$m$ 's candidate list. -
$k = 60$ is the standard smoothing constant (mitigates high sensitivity to the top few ranks).
response = client.query_points(
collection_name="financial_docs",
prefetch=[
models.Prefetch(query=sparse_vector, using="sparse", limit=50, filter=filters),
models.Prefetch(query=dense_vector, using="dense", limit=50, filter=filters),
],
query=models.FusionQuery(fusion=models.Fusion.RRF),
limit=10,
)- Zero Client Network Overhead: The candidate list retrieval, ranking, and reciprocal score accumulation execute in-memory inside Qdrant's Rust engine. Only the final top-$K$ scored points are serialized and transmitted over the network.
-
Unified for Both Hybrids: Both
BM25 + DenseandSparse + Denseutilize the identical server-side fusion pathway.