(
&self,
query_vector: &[f32],
top_k: usize,
)
| 1189 | } |
| 1190 | |
| 1191 | fn search_embeddings( |
| 1192 | &self, |
| 1193 | query_vector: &[f32], |
| 1194 | top_k: usize, |
| 1195 | ) -> PristineResult<Vec<SearchResult>> { |
| 1196 | let table = match self.txn.open_table(EMBEDDINGS) { |
| 1197 | Ok(table) => table, |
| 1198 | Err(redb::TableError::TableDoesNotExist(_)) => return Ok(Vec::new()), |
| 1199 | Err(e) => return Err(PristineError::from(e)), |
| 1200 | }; |
| 1201 | |
| 1202 | let mut scored: Vec<SearchResult> = Vec::new(); |
| 1203 | |
| 1204 | for item in table.iter()? { |
| 1205 | let (key_guard, value_guard) = item?; |
| 1206 | let key_str = key_guard.value(); |
| 1207 | |
| 1208 | let (path, chunk_idx) = match decode_embedding_key(key_str) { |
| 1209 | Some(decoded) => decoded, |
| 1210 | None => continue, |
| 1211 | }; |
| 1212 | |
| 1213 | let bytes = value_guard.value(); |
| 1214 | let record: EmbeddingRecord = |
| 1215 | postcard::from_bytes(bytes).map_err(|e| PristineError::Serialization { |
| 1216 | message: format!( |
| 1217 | "failed to deserialize EmbeddingRecord at '{}': {}", |
| 1218 | key_str, e |
| 1219 | ), |
| 1220 | })?; |
| 1221 | |
| 1222 | let score = cosine_similarity(query_vector, &record.vector); |
| 1223 | |
| 1224 | scored.push(SearchResult { |
| 1225 | path: path.to_string(), |
| 1226 | chunk_idx, |
| 1227 | score, |
| 1228 | preview: record.preview, |
| 1229 | }); |
| 1230 | } |
| 1231 | |
| 1232 | // Sort by descending score |
| 1233 | scored.sort_by(|a, b| { |
| 1234 | b.score |
| 1235 | .partial_cmp(&a.score) |
| 1236 | .unwrap_or(std::cmp::Ordering::Equal) |
| 1237 | }); |
| 1238 | |
| 1239 | // Return top-k |
| 1240 | scored.truncate(top_k); |
| 1241 | Ok(scored) |
| 1242 | } |
| 1243 | } |
| 1244 | |
| 1245 | // CrdtTxnT (read accessors) implementation for ReadTxn. |
no test coverage detected