(
&self,
query_vector: &[f32],
top_k: usize,
)
| 1234 | } |
| 1235 | |
| 1236 | fn search_embeddings( |
| 1237 | &self, |
| 1238 | query_vector: &[f32], |
| 1239 | top_k: usize, |
| 1240 | ) -> PristineResult<Vec<SearchResult>> { |
| 1241 | let table = match self.txn.open_table(EMBEDDINGS) { |
| 1242 | Ok(table) => table, |
| 1243 | Err(redb::TableError::TableDoesNotExist(_)) => return Ok(Vec::new()), |
| 1244 | Err(e) => return Err(PristineError::from(e)), |
| 1245 | }; |
| 1246 | |
| 1247 | let mut scored: Vec<SearchResult> = Vec::new(); |
| 1248 | |
| 1249 | for item in table.iter()? { |
| 1250 | let (key_guard, value_guard) = item?; |
| 1251 | let key_str = key_guard.value(); |
| 1252 | |
| 1253 | let (path, chunk_idx) = match decode_embedding_key(key_str) { |
| 1254 | Some(decoded) => decoded, |
| 1255 | None => continue, |
| 1256 | }; |
| 1257 | |
| 1258 | let bytes = value_guard.value(); |
| 1259 | let record: EmbeddingRecord = |
| 1260 | postcard::from_bytes(bytes).map_err(|e| PristineError::Serialization { |
| 1261 | message: format!( |
| 1262 | "failed to deserialize EmbeddingRecord at '{}': {}", |
| 1263 | key_str, e |
| 1264 | ), |
| 1265 | })?; |
| 1266 | |
| 1267 | let score = cosine_similarity(query_vector, &record.vector); |
| 1268 | |
| 1269 | scored.push(SearchResult { |
| 1270 | path: path.to_string(), |
| 1271 | chunk_idx, |
| 1272 | score, |
| 1273 | preview: record.preview, |
| 1274 | }); |
| 1275 | } |
| 1276 | |
| 1277 | // Sort by descending score |
| 1278 | scored.sort_by(|a, b| { |
| 1279 | b.score |
| 1280 | .partial_cmp(&a.score) |
| 1281 | .unwrap_or(std::cmp::Ordering::Equal) |
| 1282 | }); |
| 1283 | |
| 1284 | // Return top-k |
| 1285 | scored.truncate(top_k); |
| 1286 | Ok(scored) |
| 1287 | } |
| 1288 | } |
| 1289 | |
| 1290 | // CrdtTxnT (read accessors) implementation for ReadTxn. |
no test coverage detected