Remove a document from the sparse vector index.
(&self, collection: &str, doc_id: &str)
| 167 | |
| 168 | /// Remove a document from the sparse vector index. |
| 169 | pub fn remove_document(&self, collection: &str, doc_id: &str) -> crate::Result<()> { |
| 170 | let write_txn = self.db.begin_write().map_err(|e| crate::Error::Storage { |
| 171 | engine: "sparse_vector".into(), |
| 172 | detail: format!("write txn: {e}"), |
| 173 | })?; |
| 174 | { |
| 175 | let mut postings_table = |
| 176 | write_txn |
| 177 | .open_table(SPARSE_POSTINGS) |
| 178 | .map_err(|e| crate::Error::Storage { |
| 179 | engine: "sparse_vector".into(), |
| 180 | detail: format!("open postings: {e}"), |
| 181 | })?; |
| 182 | let mut norms_table = |
| 183 | write_txn |
| 184 | .open_table(SPARSE_NORMS) |
| 185 | .map_err(|e| crate::Error::Storage { |
| 186 | engine: "sparse_vector".into(), |
| 187 | detail: format!("open norms: {e}"), |
| 188 | })?; |
| 189 | |
| 190 | // Scan all posting lists for this collection and remove doc entries. |
| 191 | // This is O(vocabulary) but removal is infrequent. |
| 192 | let prefix = format!("{collection}:"); |
| 193 | let end = format!("{collection}:\u{ffff}"); |
| 194 | let keys_to_update: Vec<(String, Vec<SparsePosting>)> = { |
| 195 | let range = postings_table |
| 196 | .range(prefix.as_str()..end.as_str()) |
| 197 | .map_err(|e| crate::Error::Storage { |
| 198 | engine: "sparse_vector".into(), |
| 199 | detail: format!("range: {e}"), |
| 200 | })?; |
| 201 | let mut updates = Vec::new(); |
| 202 | for entry in range { |
| 203 | let entry = entry.map_err(|e| crate::Error::Storage { |
| 204 | engine: "sparse_vector".into(), |
| 205 | detail: format!("entry: {e}"), |
| 206 | })?; |
| 207 | let key = entry.0.value().to_string(); |
| 208 | let postings: Vec<SparsePosting> = |
| 209 | zerompk::from_msgpack(entry.1.value()).unwrap_or_default(); |
| 210 | if postings.iter().any(|p| p.doc_id == doc_id) { |
| 211 | let filtered: Vec<SparsePosting> = postings |
| 212 | .into_iter() |
| 213 | .filter(|p| p.doc_id != doc_id) |
| 214 | .collect(); |
| 215 | updates.push((key, filtered)); |
| 216 | } |
| 217 | } |
| 218 | updates |
| 219 | }; |
| 220 | |
| 221 | for (key, postings) in keys_to_update { |
| 222 | if postings.is_empty() { |
| 223 | postings_table |
| 224 | .remove(key.as_str()) |
| 225 | .map_err(|e| crate::Error::Storage { |
| 226 | engine: "sparse_vector".into(), |
no test coverage detected