uqa_storage/hnsw_index/
canonical.rs1use super::{types::active_key, HNSWIndex};
10use crate::{
11 read_control::StorageReadControl,
12 vector_index::{copy_vector, VectorRead},
13 StorageBackendResult,
14};
15use uqa_core::{memory::BudgetedVec, DocId};
16
17impl VectorRead for HNSWIndex {
18 fn check_control(&self, control: &StorageReadControl) -> StorageBackendResult<()> {
19 control.check()
20 }
21 fn dimensions(&self) -> u32 {
22 self.dimensions
23 }
24
25 fn next_document_after(
26 &self,
27 after: Option<DocId>,
28 control: &StorageReadControl,
29 ) -> StorageBackendResult<Option<DocId>> {
30 control.check()?;
31 Ok(self
32 .active
33 .next(after.map(|doc| active_key(doc, u32::MAX)))?
34 .map(|(key, _)| (key >> 32) as u64))
35 }
36
37 fn document_vector_count(
38 &self,
39 document: DocId,
40 control: &StorageReadControl,
41 ) -> StorageBackendResult<u64> {
42 let mut after = active_key(document, 0).checked_sub(1);
43 let mut count = 0;
44 while let Some((key, _)) = self.active.next(after)? {
45 control.check()?;
46 if key >> 32 != u128::from(document) {
47 break;
48 }
49 if u64::from(key as u32) != count {
50 return Err(crate::mvcc::VersionError::InvalidEncoding(
51 "HNSW live document vector ordinals are not contiguous",
52 )
53 .into_storage_error());
54 }
55 count += 1;
56 after = Some(key);
57 }
58 Ok(count)
59 }
60
61 fn read_vector(
62 &self,
63 document: DocId,
64 ordinal: u32,
65 control: &StorageReadControl,
66 ) -> StorageBackendResult<Option<BudgetedVec<f32>>> {
67 control.check()?;
68 let Some(node_id) = self.active.get(active_key(document, ordinal))? else {
69 return Ok(None);
70 };
71 let node = self
72 .node(*node_id)?
73 .filter(|node| {
74 !node.deleted && node.doc_id == document && node.vector_ordinal == ordinal
75 })
76 .ok_or_else(|| {
77 crate::mvcc::VersionError::InvalidEncoding(
78 "HNSW canonical identity has no active raw vector",
79 )
80 .into_storage_error()
81 })?;
82 copy_vector(&node.raw_vector, control).map(Some)
83 }
84}