weavatrix_search_vector/hnsw/
index_build.rs1use super::graph_build::build_graphs;
2use super::{Graph, RoutingIndex, VectorIndex};
3use crate::config::IndexConfig;
4use crate::error::SearchError;
5use crate::vector::VectorStore;
6use std::sync::Arc;
7
8impl VectorIndex {
9 pub fn build(config: IndexConfig, vectors: &[(u64, &[f32])]) -> Result<Self, SearchError> {
20 config.validate()?;
21 let vectors = Arc::new(VectorStore::build(
22 config.dimensions,
23 config.metric,
24 vectors,
25 )?);
26 let graphs = build_graphs(&vectors, &config)?;
27 let routing = RoutingIndex::build(&vectors)?;
28 Ok(Self {
29 config,
30 vectors,
31 graphs,
32 routing,
33 })
34 }
35
36 pub(crate) fn from_parts(
37 config: IndexConfig,
38 vectors: VectorStore,
39 graphs: Vec<Graph>,
40 routing: RoutingIndex,
41 ) -> Result<Self, SearchError> {
42 config.validate()?;
43 if graphs.len() != config.replicas {
44 return Err(SearchError::CorruptSnapshot(
45 "graph replica count does not match index config",
46 ));
47 }
48 if graphs
49 .iter()
50 .any(|graph| graph.nodes.len() != vectors.len())
51 {
52 return Err(SearchError::CorruptSnapshot(
53 "graph node count does not match vector count",
54 ));
55 }
56 Ok(Self {
57 config,
58 vectors: Arc::new(vectors),
59 graphs,
60 routing,
61 })
62 }
63
64 #[must_use]
65 pub fn len(&self) -> usize {
66 self.vectors.len()
67 }
68
69 #[must_use]
70 pub fn is_empty(&self) -> bool {
71 self.vectors.is_empty()
72 }
73
74 #[must_use]
75 pub const fn dimensions(&self) -> usize {
76 self.config.dimensions
77 }
78
79 #[must_use]
80 pub fn config(&self) -> &IndexConfig {
81 &self.config
82 }
83
84 #[must_use]
86 pub fn keys(&self) -> impl ExactSizeIterator<Item = u64> + '_ {
87 self.vectors.keys().iter().copied()
88 }
89
90 #[must_use]
92 pub fn vector(&self, key: u64) -> Option<&[f32]> {
93 self.vectors
94 .find_index(key)
95 .map(|index| self.vectors.vector(index))
96 }
97
98 pub(crate) fn vectors(&self) -> &VectorStore {
99 &self.vectors
100 }
101
102 pub(crate) fn graphs(&self) -> &[Graph] {
103 &self.graphs
104 }
105
106 pub(crate) fn routing(&self) -> &RoutingIndex {
107 &self.routing
108 }
109
110 #[must_use]
113 pub fn estimated_memory_bytes(&self) -> usize {
114 self.vectors
115 .estimated_bytes()
116 .saturating_add(self.graphs.iter().map(Graph::estimated_bytes).sum())
117 .saturating_add(self.routing.estimated_bytes())
118 }
119}