khive-retrieval
Hybrid retrieval composer combining HNSW vector search, BM25 keyword search, rank fusion, and optional graph/cross-encoder reranking, with deterministic scoring throughout.
Features
HybridSearchertrait — combinesVectorSearch+KeywordSearch(sameIdtype) behind onehybrid_search(query, config)callfuse_search_results/fuse_search_results_checked— fuse pre-computed vector and keyword result lists per aHybridConfig'sFusionStrategy, with min-score filtering and top-k truncation applied after fusion- Re-exports the retrieval stack —
khive-fusionandlattice-embedtypes are re-exported, andkhive-hnswandkhive-bm25types are re-exported behind thehnswandbm25features, so a caller depends on this one crate for the full hybrid path - Timeout/cancellation wrappers —
search_with_timeout,search_with_deadline,search_with_cancellationaround any search future - Feature-gated extensions — see Configuration below
Usage
use ;
let query = hybrid;
let config = new;
// vector_hits / keyword_hits come from your VectorSearch / KeywordSearch impls
// (or khive-hnsw::HnswIndex::search / khive-bm25::Bm25Index::search directly).
let fused = fuse_search_results;
for in &fused
HybridConfig::new(top_k) defaults to RRF fusion (k=60); chain
.with_fusion_strategy(..), .with_pool_size(..), .with_min_score(..), or
.with_weights(vector, keyword) to customize. In the two-arm vector/text
hybrid API, fusion sources and positional weights use [vector, keyword];
retain an empty arm as an empty vector instead of removing it, so the remaining
source keeps its assigned position. Generic RRF and Union callers may supply N
sources in their own documented order. Even a single supplied source is
transformed by the configured strategy before min_score is applied.
fuse_search_results falls back to RRF if a Weighted hybrid strategy is not
given exactly the two vector/text source slots;
fuse_search_results_checked returns Err in that case instead.
Configuration (Cargo features)
| Feature | Adds |
|---|---|
hnsw |
khive-hnsw index type re-exports (HnswIndex, HnswConfig, ...) |
bm25 |
khive-bm25 index type re-exports (Bm25Index, Bm25Config, ...) |
policy |
khive-gate-backed ClearanceLevel/SearchPolicy result filtering |
checkpoint |
HnswCheckpoint/HnswCheckpointStore re-exports (implies hnsw; snapshots via khive-fold) |
storage-adapters |
StorageVectorSearch/StorageKeywordSearch bridging sqlite-vec/FTS5 backends to the search traits |
embed |
Native lattice-embed embedding service re-exports |
native-rerank |
Cross-encoder reranking — deferred pending khive-inference port |
None of these features are enabled by default. The base crate is not
dependency-free, though: it depends on lattice-embed for native embedding. The
features above gate additional surface — HNSW/BM25 re-exports, policy filtering,
HNSW checkpointing, storage-backed search adapters, and
cross-encoder reranking — and the khive-hnsw, khive-bm25 and khive-storage
dependencies are only compiled when a feature that needs them is enabled.
SearchConfig (vector-only/keyword-only/hybrid-balanced presets) and
SearchPolicy/ClearanceLevel (with filter_by_policy/filter_by_predicate)
are also re-exported for callers that need per-result access control on top of
fusion.
Where this sits
khive-retrieval sits above khive-hnsw, khive-bm25, khive-fusion,
khive-score, and khive-types in the storage stack, and below the runtime's
ADR-012 composition layer and the kg/memory packs that call into it for
hybrid FTS5+vector search.
Governing ADRs: ADR-030 (this crate's charter — engine/adapter ownership split from ADR-012), ADR-012 (the still-live high-level composition contract), and ADR-031 (multi-engine embedder registry and pack fan-out this crate composes with).
License
Apache-2.0.