UNPKG

@claude-flow/embeddings

Version:

V3 Embedding Service - OpenAI, Transformers.js, Agentic-Flow (ONNX), Mock providers with hyperbolic embeddings, normalization, and chunking

74 lines • 3.22 kB
/** * ADR-121 Phase 11 — Reciprocal Rank Fusion (RRF). * * When you have N ranked result lists for the same query (or for N * variants of the same intent) — e.g. from a question-reformulation * pipeline, from a hybrid lexical+vector search, or from multiple * embedding models — RRF combines them into a single fused ranking * without needing the underlying scores to be comparable. * * Cormack, Clarke, Büttcher (SIGIR 2009): * * RRF_score(item) = Σ over lists i where item appears: 1 / (k_rrf + rank_i) * * where rank_i is the item's 1-based position in list i and k_rrf is a * small constant (the original paper recommends 60 — small enough that * top results dominate, large enough that mid-list ranks still * contribute). The score is heuristic but practically excellent: RRF * consistently matches or beats supervised learning-to-rank in TREC * evaluations despite needing zero training data. * * This module ships the algorithm as a pure function so callers can * compose it with any source of ranked lists — AnnRouter results, * lexical search, MMR-reranked picks, etc. The CLI's * `embeddings_search_text_ensemble` tool composes * `search_text_batch` + `reciprocalRankFusion` for the common case of * "expand one user query into N variants, retrieve top-k for each, * fuse to a single ranking". */ export interface RrfListItem { /** Caller-supplied identifier. Items with the same id across lists are fused. */ readonly id: string; /** Free-form payload — preserved from the FIRST list this item appears in. */ readonly payload?: unknown; } export interface RrfOptions { /** Number of fused results to return. Clamped to total unique items. */ readonly k: number; /** * RRF smoothing constant. Default 60 (the SIGIR 2009 recommendation). * Smaller k_rrf → top-ranked items dominate more sharply. * Larger k_rrf → flatter contribution from each list, more like simple * vote-counting. */ readonly kRrf?: number; /** Optional per-list weights. Default = 1 for every list. */ readonly listWeights?: ReadonlyArray<number>; } export interface RrfFusedHit { readonly id: string; readonly payload?: unknown; /** Final fused RRF score (higher = better). */ readonly score: number; /** * Per-list contribution: the 1-based rank in each list the item * appeared in. Length === number of input lists. `null` means the * item didn't appear in that list. */ readonly ranks: ReadonlyArray<number | null>; /** Number of lists the item appeared in. */ readonly listOccurrences: number; } /** * Iterative RRF over N ranked lists. Time complexity: * O(N · L) where N = number of lists, L = avg list length * * Lists are 1-indexed inside the formula (first item = rank 1). */ export declare function reciprocalRankFusion(lists: ReadonlyArray<ReadonlyArray<RrfListItem>>, options: RrfOptions): RrfFusedHit[]; /** * Convenience: same as reciprocalRankFusion but returns just the fused * ids in rank order. */ export declare function rrfIds(lists: ReadonlyArray<ReadonlyArray<RrfListItem>>, options: RrfOptions): string[]; //# sourceMappingURL=rrf.d.ts.map