ruvector_core/index/
flat.rs1use crate::distance::distance;
4use crate::error::Result;
5use crate::index::VectorIndex;
6use crate::types::{DistanceMetric, SearchResult, VectorId};
7use dashmap::DashMap;
8use rayon::prelude::*;
9
10pub struct FlatIndex {
12 vectors: DashMap<VectorId, Vec<f32>>,
13 metric: DistanceMetric,
14 dimensions: usize,
15}
16
17impl FlatIndex {
18 pub fn new(dimensions: usize, metric: DistanceMetric) -> Self {
20 Self {
21 vectors: DashMap::new(),
22 metric,
23 dimensions,
24 }
25 }
26}
27
28impl VectorIndex for FlatIndex {
29 fn add(&mut self, id: VectorId, vector: Vec<f32>) -> Result<()> {
30 self.vectors.insert(id, vector);
31 Ok(())
32 }
33
34 fn search(&self, query: &[f32], k: usize) -> Result<Vec<SearchResult>> {
35 let mut results: Vec<_> = self
37 .vectors
38 .iter()
39 .par_bridge()
40 .map(|entry| {
41 let id = entry.key().clone();
42 let vector = entry.value();
43 let dist = distance(query, vector, self.metric)?;
44 Ok((id, dist))
45 })
46 .collect::<Result<Vec<_>>>()?;
47
48 results.sort_by(|a, b| a.1.partial_cmp(&b.1).unwrap());
50 results.truncate(k);
51
52 Ok(results
53 .into_iter()
54 .map(|(id, score)| SearchResult {
55 id,
56 score,
57 vector: None,
58 metadata: None,
59 })
60 .collect())
61 }
62
63 fn remove(&mut self, id: &VectorId) -> Result<bool> {
64 Ok(self.vectors.remove(id).is_some())
65 }
66
67 fn len(&self) -> usize {
68 self.vectors.len()
69 }
70}
71
72#[cfg(test)]
73mod tests {
74 use super::*;
75
76 #[test]
77 fn test_flat_index() -> Result<()> {
78 let mut index = FlatIndex::new(3, DistanceMetric::Euclidean);
79
80 index.add("v1".to_string(), vec![1.0, 0.0, 0.0])?;
81 index.add("v2".to_string(), vec![0.0, 1.0, 0.0])?;
82 index.add("v3".to_string(), vec![0.0, 0.0, 1.0])?;
83
84 let query = vec![1.0, 0.0, 0.0];
85 let results = index.search(&query, 2)?;
86
87 assert_eq!(results.len(), 2);
88 assert_eq!(results[0].id, "v1");
89 assert!(results[0].score < 0.01);
90
91 Ok(())
92 }
93}