GitHub

Hybrid Search

Hybrid search is the recommended default. It runs lexical, semantic, and symbol search in parallel and fuses their rankings with Reciprocal Rank Fusion (RRF). A chunk that several modalities agree on rises to the top, and the method is immune to the fact that BM25 and cosine scores live on completely different scales.

Reciprocal Rank Fusion

RRF ignores raw scores and looks only at rank position within each modality. For every result list, a chunk at rank r (zero-indexed) contributes:

RRF contribution
score += weight / (K + rank)

RCE Code uses the canonical constant K = 60. The denominator K + rank means top-ranked items contribute the most and the contribution falls off smoothly down each list. A chunk that appears in multiple modalities accumulates the contribution from each, so cross-modality agreement is what drives final ranking. Because only ranks enter the formula, fusion is unaffected by BM25 returning, say, 8.3 while cosine returns 0.81.

Per-modality weights

The three legs are not weighted equally. Lexical and semantic each carry a weight of 1.0, while symbol matches are weighted 1.5 — an exact symbol-name hit is a strong signal, so it is boosted relative to the ranked text modalities.

SourceRRF weight
Lexical (BM25)1.0
Semantic (cosine KNN)1.0
Symbol (exact name)1.5

Over-fetch, then fuse

To give fusion enough material to work with, hybrid over-fetches each modality before combining: for a request of top_k results it pulls top_k * 3 from each leg, fuses them, then truncates the fused ranking back down to top_k. This lets a chunk ranked modestly in two modalities overtake one ranked highly in only one.

Graceful degradation

Hybrid does not require embeddings. When nothing has been embedded, the semantic leg simply returns an empty list and RRF fuses whatever lexical and symbol produced. That is why hybrid is a safe default even on a freshly indexed repo: it behaves like a fused lexical + symbol search until you run engine.embed(), at which point the semantic contribution joins automatically.

Why this is the default

Hybrid combines the precision of exact symbol and keyword matching with the recall of embeddings, normalizes away incomparable score scales via rank fusion, and degrades safely when a leg has nothing to offer. Unless you have a specific reason to pick a single modality, start here.

Python API

hybrid_search.py
from rce.code import CodeEngine
engine = CodeEngine.open_or_create("/path/to/repo")
engine.index()
engine.embed() # optional, but enables the semantic leg
for r in engine.search_hybrid("retry with exponential backoff", top_k=10):
print(round(r.score, 4), r.source, r.chunk.file_path,
f"{r.chunk.start_line}-{r.chunk.end_line}")
engine.close()

search_hybrid(query, top_k=10) returns a list[SearchResult]. Every fused result carries .source = SearchSource.HYBRID, and its .score is the accumulated RRF score (larger is better) — small absolute numbers, since each contribution is at most weight / 60.

CLI

terminal
# embed first so the semantic leg participates
rce-code embed
# fused search across lexical + semantic + symbol
rce-code search-hybrid "retry with exponential backoff"
# target another repo and cap results
rce-code search-hybrid "config loader" --repo /path/to/repo --top-k 5
example output
src/net/retry.py:12-48 (score 0.0331)
src/net/client.py:90-121 (score 0.0179)

Run embed to get the most out of it

Hybrid works without embeddings, but you only get the semantic leg after rce-code embed (or engine.embed()). The default embedder is offline, so this costs nothing but a one-time pass. See Semantic Search for details.