1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
// Note: field_reassign_with_default is needed for some internal tests
//! Hybrid search and ranking with deterministic scoring for khive.
//!
//! This crate provides:
//! - HNSW vector search with `DeterministicScore` output
//! - BM25 keyword search for exact matches
//! - Reciprocal Rank Fusion (RRF) for hybrid search
//! - Graph traversal for relationship-aware retrieval
//!
//! # Architecture
//!
//! ```text
//! ┌─────────────────────────────────────────────────────────────────┐
//! │ khive-retrieval │
//! │ ┌───────────┐ ┌───────────┐ ┌───────────┐ ┌───────────┐ │
//! │ │ hnsw/ │ │ bm25/ │ │ graph/ │ │ fusion/ │ │
//! │ │ (vector) │ │ (keyword) │ │(traversal)│ │ (RRF) │ │
//! │ └───────────┘ └───────────┘ └───────────┘ └───────────┘ │
//! │ │ │
//! │ ▼ │
//! │ ┌───────────────┐ │
//! │ │ hybrid/ │ │
//! │ │ (unified) │ │
//! │ └───────────────┘ │
//! │ │
//! │ Inputs: Query + optional embedding + optional start nodes │
//! │ Outputs: Vec<(Id, DeterministicScore)> │
//! └─────────────────────────────────────────────────────────────────┘
//! ```
//!
//! # Design Principles
//!
//! ## Deterministic Scoring (ADR-002)
//!
//! All scores use `DeterministicScore` from `khive-score` for:
//! - Cross-platform identical rankings (x86_64, ARM64, WASM)
//! - `Ord` implementation (sortable, usable in BTreeSet)
//! - `Hash` implementation (cacheable)
//!
//! ## Index Management (ADR-003)
//!
//! - HNSW: Hierarchical Navigable Small World graphs for ANN search
//! - BM25: Okapi BM25 for keyword relevance
//! - Both support incremental updates with periodic rebuild
//!
//! ## Graph Traversal (ADR-004)
//!
//! - BFS for level-by-level exploration
//! - DFS for deep path exploration
//! - Bidirectional BFS for shortest path
//!
//! ## ID Types and Bridging
//!
//! Each retrieval module uses a different ID type:
//!
//! | Module | ID Type | Backing |
//! |--------|---------|---------|
//! | HNSW | [`EmbeddingId`] | 128-bit (ULID, from khive-types) |
//! | BM25 | [`DocumentId`] | Newtype over `String` |
//! | Graph | `EntityRef` | Enum (from khive-db) |
//! | Fusion | Generic `Id` | `Eq + Hash + Clone + Ord` |
//!
//! The [`fusion::fuse`] function is generic over the ID type, so hybrid
//! search that combines results from different modules requires a common
//! representation. Bridging strategies:
//!
//! 1. **String-based**: Convert all IDs to `String` before fusion.
//! 2. **DocumentId-based**: Convert `EmbeddingId` to `DocumentId` via
//! `DocumentId::new(embedding_id.to_string())`.
//! 3. **Application-level mapping**: Maintain a bidirectional lookup table
//! between ID types in the application layer.
//!
//! See [`DocumentId`] for details on the newtype and conversion traits.
//!
//! # Quick Start
//!
//! ```rust,ignore
//! use khive_retrieval::{VectorSearch, KeywordSearch, HybridSearcher, Query, HybridConfig};
//!
//! // Implement granular traits independently:
//! // - VectorSearch for embedding-based search (HNSW)
//! // - KeywordSearch for text-based search (BM25)
//! // - HybridSearcher for combined search (requires both)
//! // - Reranker for post-retrieval reranking (standalone)
//!
//! // Example: keyword-only search
//! let results = searcher.keyword_search("distributed systems", 10).await?;
//!
//! // Example: hybrid search (vector + keyword with fusion)
//! let query = Query::hybrid("distributed systems", embedding_vec);
//! let config = HybridConfig::new(10);
//! let results = searcher.hybrid_search(&query, &config).await?;
//!
//! for (id, score) in results {
//! println!("{}: {}", id, score);
//! }
//! ```
// graph module depends on EntityRef/LinkStore/StorageContext from old monolith khive-db API;
// gated until ported to current khive-storage GraphStore trait.
// Re-export adapter types
pub use ;
// Re-export core types
pub use ;
// Re-export types from sibling crates (now separate crates)
pub use ;
pub use ;
pub use ;
pub use ;
// Formal proof: khive.Retrieval.HNSW.checkpoint_correctness
pub use ;
pub use ;
// TODO(port-rerank): native cross-encoder reranking deferred; khive-inference not ported yet
// #[cfg(feature = "native-rerank")]
// pub use hybrid::{CrossEncoderScorer, NativeCrossEncoderReranker, RerankDocumentResolver};
pub use ;
pub use ;
pub use ;
pub use ;
pub use SearchConfig;
pub use ;
/// Re-exports from `lattice-embed` for app-layer access.
///
/// Apps should use these re-exports instead of depending on `lattice-embed` directly.
/// This maintains the layer boundary: apps -> platform (retrieval) -> foundation (embed).
///
/// Core types (`EmbeddingModel`, `EmbeddingService`, `EmbedError`) are always available.
/// Native model implementations (`NativeEmbeddingService`, etc.) require the `embed` feature.