foley.index.search#
Hybrid retrieval: reciprocal rank fusion over a vector list and a keyword list.
Pure orchestration + fusion. This module depends only on the small index
protocols (foley.index.protocols) — never on torch/lancedb/
sqlite_vec — so the fusion rule is one SSOT exercised identically by every
backend and directly unit-testable.
Why rank fusion (report 04 §3.2): dense CLAP cosine lives in [-1, 1] while
BM25 scores are unbounded, so averaging them lets one drown the other.
Reciprocal Rank Fusion (RRF; Cormack, Clarke & Büttcher, SIGIR 2009) instead
fuses on rank position:
score(d) = Σ_rankers 1 / (k + rank_r(d)) # k = 60 (standard)
A document ranked high by either the vector list or the BM25 list floats up;
k=60 damps the long tail. It is one line, parameter-light, and robust — the
right first-stage fusion for a mix of semantic captions and terse literal tags.
The concrete backends (LanceDB, sqlite-vec) can fuse natively in-engine; foley deliberately fuses here instead so the ranking is byte-identical across backends and gated by the eval harness (report 08) rather than an engine’s internals.
Module Attributes
Standard RRF damping constant (Cormack et al., SIGIR 2009). |
|
Per-ranker shortlist depth pulled from each index before fusion. |
Functions
|
RRF-fuse a vector ranker's hits with a keyword ranker's hits. |
|
Embed |
|
Fuse several ranked id lists into one, by reciprocal rank. |
|
Pure audio<->audio (or clip->library) vector search — no keyword leg. |
Classes
|
One fused retrieval hit: an id plus the scores that produced it. |
- foley.index.search.DEFAULT_CANDIDATE_K: int = 50#
Per-ranker shortlist depth pulled from each index before fusion. Fusing deeper lists than the requested
klets a doc ranked mid-list by one ranker but top by the other still surface.
- class foley.index.search.FusedHit(id, rrf_score=None, clap_score=None, bm25_score=None)[source]#
Bases:
objectOne fused retrieval hit: an id plus the scores that produced it.
The raw component scores are carried through (not just the fused rank score) so the façade can stamp them onto a
Candidate(clap_score/bm25_score/rrf_score) for display and debugging.- id#
The sound id.
- rrf_score#
The fused RRF score (
Nonefor a pure-vector search).
- clap_score#
Cosine similarity from the vector ranker (
Noneif the id appeared only in the keyword list).
- bm25_score#
BM25 score from the keyword ranker (
Noneif the id appeared only in the vector list).
- foley.index.search.RRF_K: int = 60#
Standard RRF damping constant (Cormack et al., SIGIR 2009). Larger => flatter.
- foley.index.search.fuse_hits(vector_hits, keyword_hits, *, k, rrf_k=60)[source]#
RRF-fuse a vector ranker’s hits with a keyword ranker’s hits.
- Parameters:
- Return type:
- Returns:
The top-
k:class:`FusedHit`s, each carrying its raw component scores.
- foley.index.search.hybrid_search(query, *, embedder, vindex, kindex, k=10, candidate_k=50, rrf_k=60, where=None)[source]#
Embed
query, run the vector + keyword rankers, and RRF-fuse them.- Parameters:
query (
str) – The natural-language query.embedder (
Embedder) – Text<->audio embedder (itsembed_textproduces the query vector).vindex (
VectorIndex) – The vector index (CLAP KNN).kindex (
KeywordIndex) – The keyword index (BM25).k (
int) – Number of fused results to return.candidate_k (
int) – Shortlist depth pulled from each ranker before fusion.rrf_k (
int) – The RRF damping constant.where (
Optional[dict]) – Optional metadata push-down passed to both rankers.
- Return type:
- Returns:
The top-
kfused :class:`FusedHit`s.
- foley.index.search.reciprocal_rank_fusion(ranked_id_lists, *, k=60)[source]#
Fuse several ranked id lists into one, by reciprocal rank.
- Parameters:
- Return type:
- Returns:
[(id, fused_score), ...]sorted by fused score descending, ties broken byidascending (so the fusion is fully deterministic).
- foley.index.search.vector_search(qvec, *, vindex, k=10, where=None)[source]#
Pure audio<->audio (or clip->library) vector search — no keyword leg.
Used by
SoundLibrary.similarand by searching with a reference clip. Hits keep their cosine similarity inclap_scoreand preserve the index’s own descending-similarity order (rrf_scoreis leftNone— there is no fusion).- Parameters:
qvec (
ndarray) – An already-L2-normalized(dim,)query vector.vindex (
VectorIndex) – The vector index.k (
int) – Number of neighbours to return.
- Return type:
- Returns:
Up to
k:class:`FusedHit`s in descending-similarity order.