Skip to main content

oxirs_vec/
vector_index.rs

1//! In-memory vector index implementations and the `VectorIndex` trait.
2
3use anyhow::Result;
4use std::collections::HashMap;
5
6use crate::similarity;
7use crate::Vector;
8use crate::VectorId;
9
10/// Vector index trait for efficient similarity search
11pub trait VectorIndex: Send + Sync {
12    /// Insert a vector with associated URI
13    fn insert(&mut self, uri: String, vector: Vector) -> Result<()>;
14
15    /// Find k nearest neighbors
16    fn search_knn(&self, query: &Vector, k: usize) -> Result<Vec<(String, f32)>>;
17
18    /// Find all vectors within threshold similarity
19    fn search_threshold(&self, query: &Vector, threshold: f32) -> Result<Vec<(String, f32)>>;
20
21    /// Get a vector by its URI
22    fn get_vector(&self, uri: &str) -> Option<&Vector>;
23
24    /// Add a vector with associated ID and metadata
25    fn add_vector(
26        &mut self,
27        id: VectorId,
28        vector: Vector,
29        _metadata: Option<HashMap<String, String>>,
30    ) -> Result<()> {
31        // Default implementation that delegates to insert
32        self.insert(id, vector)
33    }
34
35    /// Update an existing vector
36    fn update_vector(&mut self, id: VectorId, vector: Vector) -> Result<()> {
37        // Default implementation that delegates to insert
38        self.insert(id, vector)
39    }
40
41    /// Update metadata for a vector
42    fn update_metadata(&mut self, _id: VectorId, _metadata: HashMap<String, String>) -> Result<()> {
43        // Default implementation (no-op)
44        Ok(())
45    }
46
47    /// Remove a vector by its ID
48    fn remove_vector(&mut self, _id: VectorId) -> Result<()> {
49        // Default implementation (no-op)
50        Ok(())
51    }
52
53    /// Iterate all stored (id, vector) pairs.
54    ///
55    /// The default returns an empty list; concrete index types that hold their
56    /// vectors in memory (or can reconstruct them, e.g. via decoding quantized
57    /// codes) should override this **and** [`VectorIndex::supports_enumeration`]
58    /// so callers like `VectorStore::save_to_disk` can tell real emptiness
59    /// apart from "this index type cannot enumerate its vectors".
60    fn iter_vectors(&self) -> Vec<(String, Vector)> {
61        Vec::new()
62    }
63
64    /// Whether [`VectorIndex::iter_vectors`] returns a real, complete
65    /// enumeration of the vectors held by this index.
66    ///
67    /// Index types that override `iter_vectors` with a real implementation
68    /// (e.g. [`MemoryVectorIndex`], `HnswIndex`, `IvfIndex`, `PQIndex`) must
69    /// also override this to return `true`. Callers that need to persist or
70    /// otherwise fully enumerate an index (e.g. `VectorStore::save_to_disk`)
71    /// should check this flag and fail loudly instead of silently persisting
72    /// an empty snapshot when it is `false`.
73    fn supports_enumeration(&self) -> bool {
74        false
75    }
76}
77
78/// In-memory vector index implementation
79pub struct MemoryVectorIndex {
80    vectors: Vec<(String, Vector)>,
81    similarity_config: similarity::SimilarityConfig,
82}
83
84impl MemoryVectorIndex {
85    /// Create a new empty in-memory vector index with default similarity config.
86    pub fn new() -> Self {
87        Self {
88            vectors: Vec::new(),
89            similarity_config: similarity::SimilarityConfig::default(),
90        }
91    }
92
93    /// Create a new in-memory vector index with a custom similarity configuration.
94    pub fn with_similarity_config(config: similarity::SimilarityConfig) -> Self {
95        Self {
96            vectors: Vec::new(),
97            similarity_config: config,
98        }
99    }
100}
101
102impl Default for MemoryVectorIndex {
103    fn default() -> Self {
104        Self::new()
105    }
106}
107
108impl VectorIndex for MemoryVectorIndex {
109    fn insert(&mut self, uri: String, vector: Vector) -> Result<()> {
110        // Check if vector already exists and update it
111        if let Some(pos) = self.vectors.iter().position(|(id, _)| id == &uri) {
112            self.vectors[pos] = (uri, vector);
113        } else {
114            self.vectors.push((uri, vector));
115        }
116        Ok(())
117    }
118
119    fn search_knn(&self, query: &Vector, k: usize) -> Result<Vec<(String, f32)>> {
120        let metric = self.similarity_config.primary_metric;
121        let query_f32 = query.as_f32();
122        let mut similarities: Vec<(String, f32)> = self
123            .vectors
124            .iter()
125            .map(|(uri, vec)| {
126                let vec_f32 = vec.as_f32();
127                let sim = metric.similarity(&query_f32, &vec_f32).unwrap_or(0.0);
128                (uri.clone(), sim)
129            })
130            .collect();
131
132        similarities.sort_by(|a, b| b.1.partial_cmp(&a.1).unwrap_or(std::cmp::Ordering::Equal));
133        similarities.truncate(k);
134
135        Ok(similarities)
136    }
137
138    fn search_threshold(&self, query: &Vector, threshold: f32) -> Result<Vec<(String, f32)>> {
139        let metric = self.similarity_config.primary_metric;
140        let query_f32 = query.as_f32();
141        let similarities: Vec<(String, f32)> = self
142            .vectors
143            .iter()
144            .filter_map(|(uri, vec)| {
145                let vec_f32 = vec.as_f32();
146                let sim = metric.similarity(&query_f32, &vec_f32).unwrap_or(0.0);
147                if sim >= threshold {
148                    Some((uri.clone(), sim))
149                } else {
150                    None
151                }
152            })
153            .collect();
154
155        Ok(similarities)
156    }
157
158    fn get_vector(&self, uri: &str) -> Option<&Vector> {
159        self.vectors.iter().find(|(u, _)| u == uri).map(|(_, v)| v)
160    }
161
162    fn update_vector(&mut self, id: VectorId, vector: Vector) -> Result<()> {
163        if let Some(pos) = self.vectors.iter().position(|(uri, _)| uri == &id) {
164            self.vectors[pos] = (id, vector);
165            Ok(())
166        } else {
167            Err(anyhow::anyhow!("Vector with id '{}' not found", id))
168        }
169    }
170
171    fn remove_vector(&mut self, id: VectorId) -> Result<()> {
172        if let Some(pos) = self.vectors.iter().position(|(uri, _)| uri == &id) {
173            self.vectors.remove(pos);
174            Ok(())
175        } else {
176            Err(anyhow::anyhow!("Vector with id '{}' not found", id))
177        }
178    }
179
180    fn iter_vectors(&self) -> Vec<(String, Vector)> {
181        self.vectors.clone()
182    }
183
184    fn supports_enumeration(&self) -> bool {
185        true
186    }
187}