RSF (Relative Score Fusion)

Search Engineering intermediate Building with AI 11 min read

Overview

Relative Score Fusion (RSF) is a score combination algorithm used in hybrid search systems to merge results from multiple retrieval strategies — typically dense vector (semantic) search and sparse keyword (BM25) search — into a single, unified ranked list. Unlike Reciprocal Rank Fusion (RRF), which discards raw scores and relies only on ordinal rank positions, RSF normalizes the actual numeric scores from each retrieval method and combines them via a weighted sum.

This distinction is critical: by preserving score magnitude, RSF retains far more information about each retriever’s confidence in a result. A document that scored 0.98 in semantic search is treated very differently from one that scored 0.52, even if both happen to be ranked #1 in their respective result sets from different queries. RRF would treat them identically because it only sees rank position.

RSF has become the default fusion algorithm in Weaviate (since v1.24) and is gaining adoption in other vector databases and RAG frameworks. Internal benchmarks at Weaviate showed approximately a 6% improvement in recall when switching from RRF to RSF, making it a practical upgrade for production hybrid search pipelines.

How It Works

Step 1: Independent Retrieval

The hybrid search system executes two parallel searches against the same corpus:

These two result sets often overlap partially — some documents appear in both, others in only one.

Step 2: Min-Max Normalization

Because the raw scores from vector search and keyword search live on completely different scales, they must be normalized before combination. RSF uses min-max normalization within each result set independently:

RSF Normalization Formula

normalized_score = (score - min_score) / (max_score - min_score)

The highest-scoring document in each result set gets a normalized score of 1.0, the lowest gets 0.0, and everything in between is linearly interpolated based on its relative distance from the extremes.

For example, if your BM25 results range from 3.2 to 15.8, a document scoring 9.5 would be normalized to (9.5 - 3.2) / (15.8 - 3.2) = 0.50. Meanwhile, if your vector results range from 0.71 to 0.96, a document scoring 0.89 normalizes to (0.89 - 0.71) / (0.96 - 0.71) = 0.72.

Step 3: Weighted Combination

After normalization, each document’s scores are combined using a weighted sum controlled by a parameter typically called alpha:

Weighted Sum Formula

final_score = alpha * vector_score + (1 - alpha) * keyword_score

When alpha = 0.75 (a common default), the system weights semantic similarity three times more heavily than keyword matching. Documents appearing in only one result set receive 0 for the missing score.

Step 4: Merge and Sort

The system creates a union of all documents from both result sets. Each document gets its final weighted score. Documents that appeared in both searches benefit from dual contributions. The final list is sorted by descending combined score and the top-K results are returned.

Handling Edge Cases

When a result set contains only one document, the min and max scores are identical, making the denominator zero. Implementations typically handle this by assigning a normalized score of 1.0 to the sole result. Documents appearing in only one retriever’s results receive a 0 for the other retriever’s normalized score, which naturally down-weights single-source results compared to documents found by both retrievers.

Code Example

import numpy as np

def relative_score_fusion(vector_results, keyword_results, alpha=0.75):
    """
    Fuse two ranked result lists using Relative Score Fusion.
    Each result is a list of (doc_id, raw_score) tuples.
    """
    def normalize(results):
        if not results:
            return {}
        scores = [s for _, s in results]
        min_s, max_s = min(scores), max(scores)
        denom = max_s - min_s if max_s != min_s else 1.0
        return {doc_id: (s - min_s) / denom for doc_id, s in results}

    vec_norm = normalize(vector_results)
    kw_norm = normalize(keyword_results)

    # Union of all document IDs
    all_docs = set(vec_norm.keys()) | set(kw_norm.keys())

    fused = {}
    for doc_id in all_docs:
        v_score = vec_norm.get(doc_id, 0.0)
        k_score = kw_norm.get(doc_id, 0.0)
        fused[doc_id] = alpha * v_score + (1 - alpha) * k_score

    # Sort by fused score descending
    return sorted(fused.items(), key=lambda x: x[1], reverse=True)

# Example usage
vector_hits = [("doc_A", 0.96), ("doc_B", 0.89), ("doc_C", 0.71)]
keyword_hits = [("doc_B", 15.8), ("doc_D", 9.5), ("doc_C", 3.2)]

ranked = relative_score_fusion(vector_hits, keyword_hits, alpha=0.75)
# doc_B benefits from appearing in both lists with high scores

RSF vs. RRF: A Direct Comparison

Understanding when to choose RSF over RRF is essential for optimizing your hybrid search pipeline:

Information Preservation

RRF reduces each document to an ordinal rank (1st, 2nd, 3rd…) and computes 1 / (k + rank). This means a document ranked #1 with a score of 0.99 and another ranked #1 with a score of 0.51 receive identical RRF contributions. RSF preserves the gap between these scores, giving the 0.99 document significantly more weight.

Score Variance Compression

RRF compresses score variance because the reciprocal rank function flattens differences — the gap between rank 1 and rank 2 (1/61 - 1/62 = 0.00027 with k=60) is tiny. RSF maintains the original distribution’s shape, so a cluster of very similar top results is correctly reflected as a tight group, while outlier scores stand out.

Sensitivity to Alpha Tuning

RSF’s alpha parameter gives you fine-grained control over the balance between semantic and keyword results. At alpha = 1.0, it becomes pure vector search; at alpha = 0.0, pure keyword search. RRF’s equivalent parameter has less practical effect because rank-based scores already occupy a narrow range.

When RRF Still Wins

RRF is simpler to implement and more robust when the raw scores from your retrievers are unreliable or poorly calibrated. If your BM25 implementation produces noisy or inconsistent scores across different query types, normalizing those scores may amplify noise rather than signal. RRF sidesteps this entirely by ignoring magnitudes.

Practical Applications

RAG Pipelines

In Retrieval-Augmented Generation, the quality of retrieved context directly impacts LLM output quality. RSF improves RAG by ensuring high-confidence results from either retriever are properly surfaced. A document that’s a near-perfect semantic match (0.97 cosine similarity) will rank highly even if it doesn’t contain the exact keywords, while an exact keyword match with moderate semantic relevance also gets fair treatment.

Product search benefits from RSF because users often combine intent (semantic: “comfortable running shoes for flat feet”) with specific requirements (keyword: “Nike size 12”). RSF’s weighted combination lets you tune the alpha parameter per query type — more semantic weight for natural language queries, more keyword weight for SKU or model number searches.

Weaviate Configuration

In Weaviate, RSF is the default fusion algorithm since v1.24. You can configure it explicitly when creating a collection:

# Weaviate Python client v4
import weaviate.classes as wvc

collection = client.collections.create(
    name="Documents",
    vectorizer_config=wvc.config.Configure.Vectorizer.text2vec_openai(),
    properties=[
        wvc.config.Property(name="content", data_type=wvc.config.DataType.TEXT),
    ]
)

# Hybrid search with RSF (default) and custom alpha
response = collection.query.hybrid(
    query="machine learning optimization techniques",
    alpha=0.75,  # 75% vector, 25% keyword
    limit=10,
    fusion_type=wvc.query.HybridFusion.RELATIVE_SCORE  # explicit
)

Distribution-Based Score Fusion (DBSF)

An emerging variation called Distribution-Based Score Fusion normalizes scores using the statistical distribution (mean and standard deviation) rather than simple min-max. This is more robust to outliers — a single anomalously high BM25 score won’t compress all other scores toward zero. DBSF is available in frameworks like LlamaIndex and represents the next evolution of score-based fusion.

Key Takeaways

Further Reading