1use selene_core::{Change, DbString, HnswIndexConfig, SchemaChange, SchemaVectorIndexKind};
4
5use crate::graph::VectorIndexEntry;
6use crate::{GraphError, GraphResult, Mutator, VectorIndexConfig, VectorIndexKind};
7
8impl<'tx, 'g> Mutator<'tx, 'g> {
9 pub fn create_vector_index(
18 &mut self,
19 label: DbString,
20 property: DbString,
21 kind: VectorIndexKind,
22 dimension: u32,
23 ) -> GraphResult<()> {
24 self.create_vector_index_named(label, property, kind, dimension, None)
25 }
26
27 pub fn create_vector_index_named(
29 &mut self,
30 label: DbString,
31 property: DbString,
32 kind: VectorIndexKind,
33 dimension: u32,
34 name: Option<DbString>,
35 ) -> GraphResult<()> {
36 self.create_vector_index_named_with_config(label, property, kind, dimension, name, None)
37 }
38
39 pub fn create_vector_index_named_with_config(
41 &mut self,
42 label: DbString,
43 property: DbString,
44 kind: VectorIndexKind,
45 dimension: u32,
46 name: Option<DbString>,
47 hnsw_config: Option<HnswIndexConfig>,
48 ) -> GraphResult<()> {
49 self.create_vector_index_named_with_configs(
50 label,
51 property,
52 kind,
53 dimension,
54 name,
55 VectorIndexConfig::new(hnsw_config, None),
56 )
57 }
58
59 pub fn create_vector_index_named_with_configs(
61 &mut self,
62 label: DbString,
63 property: DbString,
64 kind: VectorIndexKind,
65 dimension: u32,
66 name: Option<DbString>,
67 config: VectorIndexConfig,
68 ) -> GraphResult<()> {
69 if self
70 .txn
71 .read()
72 .vector_index
73 .contains_key(&(label.clone(), property.clone()))
74 {
75 return Err(GraphError::VectorIndexAlreadyExists { label, property });
76 }
77 let index = crate::vector_index::build_vector_index_with_configs(
78 self.txn.read(),
79 label.clone(),
80 property.clone(),
81 kind,
82 dimension,
83 config,
84 )?;
85 let hnsw_config = index.hnsw_config();
86 let ivf_config = index.ivf_config();
87 let graph_id = self.txn.read().graph_id();
88 self.txn.guard_mut().vector_index.insert(
89 (label.clone(), property.clone()),
90 VectorIndexEntry::new(index, name.clone()),
91 );
92 self.txn.changes.push(Change::SchemaChanged {
93 graph: graph_id,
94 change: SchemaChange::VectorIndexCreated {
95 label,
96 property,
97 kind: schema_kind_from(kind),
98 dimension,
99 name,
100 hnsw_config,
101 ivf_config,
102 },
103 });
104 Ok(())
105 }
106
107 pub fn drop_vector_index(&mut self, label: DbString, property: DbString) -> GraphResult<()> {
112 if !self
113 .txn
114 .read()
115 .vector_index
116 .contains_key(&(label.clone(), property.clone()))
117 {
118 return Ok(());
119 }
120 let graph_id = self.txn.read().graph_id();
121 self.txn
122 .guard_mut()
123 .vector_index
124 .remove(&(label.clone(), property.clone()));
125 self.txn.changes.push(Change::SchemaChanged {
126 graph: graph_id,
127 change: SchemaChange::VectorIndexDropped { label, property },
128 });
129 Ok(())
130 }
131}
132
133const fn schema_kind_from(kind: VectorIndexKind) -> SchemaVectorIndexKind {
134 match kind {
135 VectorIndexKind::Flat => SchemaVectorIndexKind::Flat,
136 VectorIndexKind::HnswSquaredEuclidean => SchemaVectorIndexKind::HnswSquaredEuclidean,
137 VectorIndexKind::HnswCosine => SchemaVectorIndexKind::HnswCosine,
138 VectorIndexKind::HnswNegativeInnerProduct => {
139 SchemaVectorIndexKind::HnswNegativeInnerProduct
140 }
141 VectorIndexKind::IvfSquaredEuclidean => SchemaVectorIndexKind::IvfSquaredEuclidean,
142 VectorIndexKind::IvfCosine => SchemaVectorIndexKind::IvfCosine,
143 VectorIndexKind::IvfNegativeInnerProduct => SchemaVectorIndexKind::IvfNegativeInnerProduct,
144 VectorIndexKind::TurboQuantCosine => SchemaVectorIndexKind::TurboQuantCosine,
145 }
146}
147
148#[cfg(test)]
149#[path = "vector_index/tests.rs"]
150mod tests;