Skip to main content

rrf_explain

Function rrf_explain 

Source
pub fn rrf_explain<I, L>(
    lists: &[L],
    retriever_ids: &[RetrieverId],
    config: RrfConfig,
) -> Vec<FusedResult<I>>
where I: Clone + Eq + Hash, L: AsRef<[(I, f32)]>,
Expand description

RRF with explainability: returns full provenance for each result.

This variant preserves which retrievers contributed each document, their original ranks, and how much each source contributed to the final RRF score.

§Arguments

  • lists - Ranked lists from each retriever
  • retriever_ids - Identifiers for each retriever (must match lists.len())
  • config - RRF configuration

§Returns

Results sorted by fused score (descending), with full explanation metadata.

§Example

use rankops::explain::{rrf_explain, RetrieverId};
use rankops::RrfConfig;

let bm25 = vec![("d1", 12.5), ("d2", 11.0)];
let dense = vec![("d2", 0.9), ("d3", 0.8)];

let retrievers = vec![
    RetrieverId::new("bm25"),
    RetrieverId::new("dense"),
];

let explained = rrf_explain(
    &[&bm25[..], &dense[..]],
    &retrievers,
    RrfConfig::default(),
);

// d2 appears in both lists at rank 1 and 0 respectively
let d2 = explained.iter().find(|r| r.id == "d2").unwrap();
assert_eq!(d2.explanation.sources.len(), 2);
assert_eq!(d2.explanation.consensus_score, 1.0); // in both lists

// Check contributions
let bm25_contrib = d2.explanation.sources.iter()
    .find(|s| s.retriever_id == "bm25")
    .unwrap();
assert_eq!(bm25_contrib.original_rank, Some(1));
assert!(bm25_contrib.contribution > 0.0);