grafeo_core/graph/lpg/store/
index.rs1use super::LpgStore;
4use dashmap::DashMap;
5use grafeo_common::types::{HashableValue, NodeId, PropertyKey, Value};
6use grafeo_common::utils::hash::FxHashSet;
7#[cfg(any(feature = "vector-index", feature = "text-index"))]
8use parking_lot::RwLock;
9#[cfg(any(feature = "vector-index", feature = "text-index"))]
10use std::sync::Arc;
11
12#[cfg(feature = "vector-index")]
13use crate::index::vector::HnswIndex;
14
15impl LpgStore {
16 pub fn create_property_index(&self, property: &str) {
42 let key = PropertyKey::new(property);
43
44 let mut indexes = self.property_indexes.write();
45 if indexes.contains_key(&key) {
46 return; }
48
49 let index: DashMap<HashableValue, FxHashSet<NodeId>> = DashMap::new();
51
52 for node_id in self.node_ids() {
54 if let Some(value) = self.node_properties.get(node_id, &key) {
55 let hv = HashableValue::new(value);
56 index.entry(hv).or_default().insert(node_id);
57 }
58 }
59
60 indexes.insert(key, index);
61 }
62
63 pub fn drop_property_index(&self, property: &str) -> bool {
67 let key = PropertyKey::new(property);
68 self.property_indexes.write().remove(&key).is_some()
69 }
70
71 #[must_use]
73 pub fn has_property_index(&self, property: &str) -> bool {
74 let key = PropertyKey::new(property);
75 self.property_indexes.read().contains_key(&key)
76 }
77
78 pub(super) fn update_property_index_on_set(
80 &self,
81 node_id: NodeId,
82 key: &PropertyKey,
83 new_value: &Value,
84 ) {
85 let indexes = self.property_indexes.read();
86 if let Some(index) = indexes.get(key) {
87 if let Some(old_value) = self.node_properties.get(node_id, key) {
89 let old_hv = HashableValue::new(old_value);
90 if let Some(mut nodes) = index.get_mut(&old_hv) {
91 nodes.remove(&node_id);
92 if nodes.is_empty() {
93 drop(nodes);
94 index.remove(&old_hv);
95 }
96 }
97 }
98
99 let new_hv = HashableValue::new(new_value.clone());
101 index
102 .entry(new_hv)
103 .or_insert_with(FxHashSet::default)
104 .insert(node_id);
105 }
106 }
107
108 pub(super) fn update_property_index_on_remove(&self, node_id: NodeId, key: &PropertyKey) {
110 let indexes = self.property_indexes.read();
111 if let Some(index) = indexes.get(key) {
112 if let Some(old_value) = self.node_properties.get(node_id, key) {
114 let old_hv = HashableValue::new(old_value);
115 if let Some(mut nodes) = index.get_mut(&old_hv) {
116 nodes.remove(&node_id);
117 if nodes.is_empty() {
118 drop(nodes);
119 index.remove(&old_hv);
120 }
121 }
122 }
123 }
124 }
125
126 #[cfg(feature = "vector-index")]
128 pub fn add_vector_index(&self, label: &str, property: &str, index: Arc<HnswIndex>) {
129 let key = format!("{label}:{property}");
130 self.vector_indexes.write().insert(key, index);
131 }
132
133 #[cfg(feature = "vector-index")]
135 #[must_use]
136 pub fn get_vector_index(&self, label: &str, property: &str) -> Option<Arc<HnswIndex>> {
137 let key = format!("{label}:{property}");
138 self.vector_indexes.read().get(&key).cloned()
139 }
140
141 #[cfg(feature = "vector-index")]
145 pub fn remove_vector_index(&self, label: &str, property: &str) -> bool {
146 let key = format!("{label}:{property}");
147 self.vector_indexes.write().remove(&key).is_some()
148 }
149
150 #[cfg(feature = "vector-index")]
154 #[must_use]
155 pub fn vector_index_entries(&self) -> Vec<(String, Arc<HnswIndex>)> {
156 self.vector_indexes
157 .read()
158 .iter()
159 .map(|(k, v)| (k.clone(), v.clone()))
160 .collect()
161 }
162
163 #[cfg(feature = "text-index")]
165 pub fn add_text_index(
166 &self,
167 label: &str,
168 property: &str,
169 index: Arc<RwLock<crate::index::text::InvertedIndex>>,
170 ) {
171 let key = format!("{label}:{property}");
172 self.text_indexes.write().insert(key, index);
173 }
174
175 #[cfg(feature = "text-index")]
177 #[must_use]
178 pub fn get_text_index(
179 &self,
180 label: &str,
181 property: &str,
182 ) -> Option<Arc<RwLock<crate::index::text::InvertedIndex>>> {
183 let key = format!("{label}:{property}");
184 self.text_indexes.read().get(&key).cloned()
185 }
186
187 #[cfg(feature = "text-index")]
191 pub fn remove_text_index(&self, label: &str, property: &str) -> bool {
192 let key = format!("{label}:{property}");
193 self.text_indexes.write().remove(&key).is_some()
194 }
195
196 #[cfg(feature = "text-index")]
200 pub fn text_index_entries(
201 &self,
202 ) -> Vec<(String, Arc<RwLock<crate::index::text::InvertedIndex>>)> {
203 self.text_indexes
204 .read()
205 .iter()
206 .map(|(k, v)| (k.clone(), v.clone()))
207 .collect()
208 }
209
210 #[cfg(feature = "text-index")]
215 pub(super) fn update_text_index_on_set(&self, id: NodeId, key: &str, value: &Value) {
216 let text_indexes = self.text_indexes.read();
217 if text_indexes.is_empty() {
218 return;
219 }
220 let id_to_label = self.id_to_label.read();
221 let node_labels = self.node_labels.read();
222 if let Some(label_ids) = node_labels.get(&id) {
223 for &label_id in label_ids {
224 if let Some(label_name) = id_to_label.get(label_id as usize) {
225 let index_key = format!("{label_name}:{key}");
226 if let Some(index) = text_indexes.get(&index_key) {
227 let mut idx = index.write();
228 idx.remove(id);
230 if let Value::String(text) = value {
231 idx.insert(id, text);
232 }
233 }
234 }
235 }
236 }
237 }
238
239 #[cfg(feature = "text-index")]
241 pub(super) fn update_text_index_on_remove(&self, id: NodeId, key: &str) {
242 let text_indexes = self.text_indexes.read();
243 if text_indexes.is_empty() {
244 return;
245 }
246 let id_to_label = self.id_to_label.read();
247 let node_labels = self.node_labels.read();
248 if let Some(label_ids) = node_labels.get(&id) {
249 for &label_id in label_ids {
250 if let Some(label_name) = id_to_label.get(label_id as usize) {
251 let index_key = format!("{label_name}:{key}");
252 if let Some(index) = text_indexes.get(&index_key) {
253 index.write().remove(id);
254 }
255 }
256 }
257 }
258 }
259
260 #[cfg(feature = "text-index")]
262 pub(super) fn remove_from_all_text_indexes(&self, id: NodeId) {
263 let text_indexes = self.text_indexes.read();
264 if text_indexes.is_empty() {
265 return;
266 }
267 for (_, index) in text_indexes.iter() {
268 index.write().remove(id);
269 }
270 }
271}