---
title: "ReciprocalRankFusion"
manual: "TYPO3 LLM Extension"
version: "0.35"
permalink: "https://docs.typo3.org/permalink/netresearch/nr-llm:api-reciprocal-rank-fusion@0.35"
source: "Api/ReciprocalRankFusion.rst"
modified: "2026-09-16T22:09:16+00:00"
---

# ReciprocalRankFusion

-   **class ReciprocalRankFusion**

    -   *Fully qualified name:* `\Netresearch\NrLlm\Service\Retrieval\ReciprocalRankFusion`

    Reciprocal Rank Fusion (Cormack et al., 2009) for hybrid retrieval
    ([ADR-074: Reciprocal Rank Fusion as a hosted utility](https://docs.typo3.org/permalink/netresearch/nr-llm:adr-074@0.35)). Fuses several ranked key lists using only per-list
    rank, never score magnitude — so it combines rankings on incomparable
    score scales (dense cosine similarity, sparse BM25) without any
    normalization.

    Final readonly class, newable: construct it with `new`, it is not a
    DI service. nr_llm's own retrieval cascade ([ADR-049: RAG site-search tools over installed search indexes](https://docs.typo3.org/permalink/netresearch/nr-llm:adr-049@0.35)) does not
    call it — it exists for hybrid consumers that fan out to several
    retrieval arms themselves.

    -   **fuse(array $rankedKeyLists, int $k = 60, array $weights = \[\]) : array**

        Fuse ranked key lists into one list ordered by descending RRF
        score. For each key the fused score is
        Σ`i` weight`i` / (k + rank`i`), where
        rank`i` is the key's 1-based position in list *i*; a key
        absent from a list contributes nothing there. Duplicates within a
        list are ignored past their first rank. Equal scores keep
        first-seen order (list 0 before list 1's new keys). A `$k`
        below 1 is clamped to 1.

        -   *param array $rankedKeyLists:*

            list\<list\<string>> — each inner list
            is keys best-first

        -   *param int $k:*

            rank-smoothing constant; smaller values let top
            ranks dominate

        -   *param array $weights:*

            list\<float> — per-list weight (same index);
            missing or extra entries default to 1.0

        *Returns:* list\<int|string> — fused keys, highest RRF score first. PHP array-key coercion applies: numeric-string keys (e.g. `'42'`) come back as `int`, so compare fused keys loosely or cast before a strict comparison.

## Usage

```php
use Netresearch\NrLlm\Service\Retrieval\ReciprocalRankFusion;

$denseKeys = ['page:12', 'page:7', 'page:3'];   // embedding arm, best-first
$sparseKeys = ['page:7', 'page:9'];             // keyword arm, best-first

$fused = (new ReciprocalRankFusion())->fuse(
    [$denseKeys, $sparseKeys],
    60,
    [1.0, 0.5],  // trust the dense arm twice as much
);
// ['page:7', ...] — ranked in both arms, so it wins
```
