(
&self,
query_vector: &[f32],
top_k: usize,
)
| 1060 | } |
| 1061 | |
| 1062 | fn search_embeddings( |
| 1063 | &self, |
| 1064 | query_vector: &[f32], |
| 1065 | top_k: usize, |
| 1066 | ) -> PristineResult<Vec<SearchResult>> { |
| 1067 | let table = match self.txn.open_table(EMBEDDINGS) { |
| 1068 | Ok(table) => table, |
| 1069 | Err(redb::TableError::TableDoesNotExist(_)) => return Ok(Vec::new()), |
| 1070 | Err(e) => return Err(PristineError::from(e)), |
| 1071 | }; |
| 1072 | |
| 1073 | let mut scored: Vec<SearchResult> = Vec::new(); |
| 1074 | |
| 1075 | for item in table.iter()? { |
| 1076 | let (key_guard, value_guard) = item?; |
| 1077 | let key_str = key_guard.value(); |
| 1078 | |
| 1079 | let (path, chunk_idx) = match decode_embedding_key(key_str) { |
| 1080 | Some(decoded) => decoded, |
| 1081 | None => continue, |
| 1082 | }; |
| 1083 | |
| 1084 | let bytes = value_guard.value(); |
| 1085 | let record: EmbeddingRecord = |
| 1086 | postcard::from_bytes(bytes).map_err(|e| PristineError::Serialization { |
| 1087 | message: format!( |
| 1088 | "failed to deserialize EmbeddingRecord at '{}': {}", |
| 1089 | key_str, e |
| 1090 | ), |
| 1091 | })?; |
| 1092 | |
| 1093 | let score = cosine_similarity(query_vector, &record.vector); |
| 1094 | |
| 1095 | scored.push(SearchResult { |
| 1096 | path: path.to_string(), |
| 1097 | chunk_idx, |
| 1098 | score, |
| 1099 | preview: record.preview, |
| 1100 | }); |
| 1101 | } |
| 1102 | |
| 1103 | // Sort by descending score |
| 1104 | scored.sort_by(|a, b| { |
| 1105 | b.score |
| 1106 | .partial_cmp(&a.score) |
| 1107 | .unwrap_or(std::cmp::Ordering::Equal) |
| 1108 | }); |
| 1109 | |
| 1110 | // Return top-k |
| 1111 | scored.truncate(top_k); |
| 1112 | Ok(scored) |
| 1113 | } |
| 1114 | } |
| 1115 | |
| 1116 | // CrdtTxnT (read accessors) implementation for ReadTxn. |
no test coverage detected