1use std::collections::HashMap;
8use std::time::Duration;
9
10use common::StorageConfig;
11use serde::{Deserialize, Serialize};
12
13pub use crate::serde::FieldType;
15pub use crate::serde::collection_meta::DistanceMetric;
16
17pub const VECTOR_FIELD_NAME: &str = "vector";
19
20#[derive(Debug, Clone)]
42pub struct Vector {
43 pub id: String,
45
46 pub attributes: Vec<Attribute>,
48}
49
50impl Vector {
51 pub fn new(id: impl Into<String>, values: Vec<f32>) -> Self {
55 Self {
56 id: id.into(),
57 attributes: vec![Attribute::new(
58 VECTOR_FIELD_NAME,
59 AttributeValue::Vector(values),
60 )],
61 }
62 }
63
64 pub fn builder(id: impl Into<String>, values: Vec<f32>) -> VectorBuilder {
68 VectorBuilder {
69 id: id.into(),
70 attributes: vec![Attribute::new(
71 VECTOR_FIELD_NAME,
72 AttributeValue::Vector(values),
73 )],
74 }
75 }
76
77 pub fn attribute(&self, name: &str) -> Option<&AttributeValue> {
78 self.attributes
79 .iter()
80 .filter(|a| a.name == name)
81 .map(|a| &a.value)
82 .next()
83 }
84}
85
86#[derive(Debug)]
88pub struct VectorBuilder {
89 id: String,
90 attributes: Vec<Attribute>,
91}
92
93impl VectorBuilder {
94 pub fn attribute(mut self, name: impl Into<String>, value: impl Into<AttributeValue>) -> Self {
96 self.attributes
97 .push(Attribute::new(name.into(), value.into()));
98 self
99 }
100
101 pub fn build(self) -> Vector {
103 Vector {
104 id: self.id,
105 attributes: self.attributes,
106 }
107 }
108}
109
110#[derive(Debug, Clone, PartialEq)]
116pub struct Attribute {
117 pub name: String,
118 pub value: AttributeValue,
119}
120
121impl Attribute {
122 pub fn new(name: impl Into<String>, value: AttributeValue) -> Self {
123 Self {
124 name: name.into(),
125 value,
126 }
127 }
128}
129
130#[derive(Debug, Clone, PartialEq)]
135pub enum AttributeValue {
136 String(String),
137 Int64(i64),
138 Float64(f64),
139 Bool(bool),
140 Vector(Vec<f32>),
141}
142
143impl From<String> for AttributeValue {
145 fn from(s: String) -> Self {
146 AttributeValue::String(s)
147 }
148}
149
150impl From<&str> for AttributeValue {
151 fn from(s: &str) -> Self {
152 AttributeValue::String(s.to_string())
153 }
154}
155
156impl From<i64> for AttributeValue {
157 fn from(v: i64) -> Self {
158 AttributeValue::Int64(v)
159 }
160}
161
162impl From<f64> for AttributeValue {
163 fn from(v: f64) -> Self {
164 AttributeValue::Float64(v)
165 }
166}
167
168impl From<bool> for AttributeValue {
169 fn from(v: bool) -> Self {
170 AttributeValue::Bool(v)
171 }
172}
173
174impl From<crate::serde::FieldValue> for AttributeValue {
175 fn from(field: crate::serde::FieldValue) -> Self {
176 match field {
177 crate::serde::FieldValue::String(s) => AttributeValue::String(s),
178 crate::serde::FieldValue::Int64(v) => AttributeValue::Int64(v),
179 crate::serde::FieldValue::Float64(v) => AttributeValue::Float64(v),
180 crate::serde::FieldValue::Bool(v) => AttributeValue::Bool(v),
181 crate::serde::FieldValue::Vector(v) => AttributeValue::Vector(v),
182 }
183 }
184}
185
186#[derive(Debug, Clone, Serialize, Deserialize)]
188pub struct Config {
189 pub storage: StorageConfig,
194
195 pub dimensions: u16,
200
201 pub distance_metric: DistanceMetric,
203
204 #[serde(with = "duration_secs")]
206 pub flush_interval: Duration,
207
208 pub split_threshold_vectors: usize,
210
211 pub merge_threshold_vectors: usize,
213
214 pub split_search_neighbourhood: usize,
216
217 pub max_pending_and_running_rebalance_tasks: usize,
220
221 pub rebalance_backpressure_resume_threshold: usize,
224
225 pub max_rebalance_tasks: usize,
227
228 pub chunk_target: u16,
230
231 pub query_pruning_factor: Option<f32>,
241
242 pub metadata_fields: Vec<MetadataFieldSpec>,
248}
249
250impl Default for Config {
251 fn default() -> Self {
252 Self {
253 storage: StorageConfig::InMemory,
254 dimensions: 0, distance_metric: DistanceMetric::L2,
256 flush_interval: Duration::from_secs(60),
257 split_threshold_vectors: 2_000,
258 merge_threshold_vectors: 500,
259 split_search_neighbourhood: 16,
260 max_pending_and_running_rebalance_tasks: 16,
261 rebalance_backpressure_resume_threshold: 8,
262 max_rebalance_tasks: 8,
263 chunk_target: 4096,
264 query_pruning_factor: None,
265 metadata_fields: Vec::new(),
266 }
267 }
268}
269
270#[derive(Debug, Clone, Serialize, Deserialize)]
272pub struct ReaderConfig {
273 pub storage: StorageConfig,
275
276 pub dimensions: u16,
278
279 pub distance_metric: DistanceMetric,
281
282 pub query_pruning_factor: Option<f32>,
286
287 pub metadata_fields: Vec<MetadataFieldSpec>,
289}
290
291#[derive(Debug, Clone, Serialize, Deserialize)]
293pub struct MetadataFieldSpec {
294 pub name: String,
296
297 pub field_type: FieldType,
299
300 pub indexed: bool,
303}
304
305impl MetadataFieldSpec {
306 pub fn new(name: impl Into<String>, field_type: FieldType, indexed: bool) -> Self {
307 Self {
308 name: name.into(),
309 field_type,
310 indexed,
311 }
312 }
313}
314
315#[derive(Debug, Clone)]
317pub struct SearchResult {
318 pub score: f32,
323 pub vector: Vector,
325}
326
327#[derive(Debug, Clone)]
337pub struct Query {
338 pub vector: Vec<f32>,
340 pub limit: usize,
342 pub filter: Option<Filter>,
344}
345
346impl Query {
347 pub fn new(vector: Vec<f32>) -> Self {
349 Self {
350 vector,
351 limit: 10,
352 filter: None,
353 }
354 }
355
356 pub fn with_limit(mut self, limit: usize) -> Self {
358 self.limit = limit;
359 self
360 }
361
362 pub fn with_filter(mut self, filter: Filter) -> Self {
364 self.filter = Some(filter);
365 self
366 }
367}
368
369#[derive(Debug, Clone, PartialEq)]
374pub enum Filter {
375 Eq(String, AttributeValue),
377 Neq(String, AttributeValue),
379 In(String, Vec<AttributeValue>),
381 And(Vec<Filter>),
383 Or(Vec<Filter>),
385}
386
387impl Filter {
388 pub fn eq(field: impl Into<String>, value: impl Into<AttributeValue>) -> Self {
390 Filter::Eq(field.into(), value.into())
391 }
392
393 pub fn neq(field: impl Into<String>, value: impl Into<AttributeValue>) -> Self {
395 Filter::Neq(field.into(), value.into())
396 }
397
398 pub fn in_set(field: impl Into<String>, values: Vec<AttributeValue>) -> Self {
400 Filter::In(field.into(), values)
401 }
402
403 pub fn and(filters: Vec<Filter>) -> Self {
405 Filter::And(filters)
406 }
407
408 pub fn or(filters: Vec<Filter>) -> Self {
410 Filter::Or(filters)
411 }
412}
413
414pub(crate) fn attributes_to_map(attributes: &[Attribute]) -> HashMap<String, AttributeValue> {
416 attributes
417 .iter()
418 .map(|attr| (attr.name.clone(), attr.value.clone()))
419 .collect()
420}
421
422mod duration_secs {
423 use std::time::Duration;
424
425 use serde::{Deserialize, Deserializer, Serializer};
426
427 pub fn serialize<S: Serializer>(d: &Duration, s: S) -> Result<S::Ok, S::Error> {
428 s.serialize_u64(d.as_secs())
429 }
430
431 pub fn deserialize<'de, D: Deserializer<'de>>(d: D) -> Result<Duration, D::Error> {
432 let secs = u64::deserialize(d)?;
433 Ok(Duration::from_secs(secs))
434 }
435}
436
437#[cfg(test)]
438mod tests {
439 use super::*;
440
441 #[test]
442 fn should_create_vector_with_builder() {
443 let vector = Vector::builder("test-id", vec![1.0, 2.0, 3.0])
445 .attribute("category", "test")
446 .attribute("count", 42i64)
447 .attribute("score", 0.95)
448 .attribute("enabled", true)
449 .build();
450
451 assert_eq!(vector.id, "test-id");
453 assert_eq!(vector.attributes.len(), 5);
455 assert_eq!(vector.attributes[0].name, "vector");
457 assert_eq!(
458 vector.attributes[0].value,
459 AttributeValue::Vector(vec![1.0, 2.0, 3.0])
460 );
461 assert_eq!(vector.attributes[1].name, "category");
463 assert_eq!(
464 vector.attributes[1].value,
465 AttributeValue::String("test".to_string())
466 );
467 }
468
469 #[test]
470 fn should_create_vector_without_extra_attributes() {
471 let vector = Vector::new("test-id", vec![1.0, 2.0, 3.0]);
473
474 assert_eq!(vector.id, "test-id");
476 assert_eq!(vector.attributes.len(), 1);
478 assert_eq!(vector.attributes[0].name, "vector");
479 assert_eq!(
480 vector.attributes[0].value,
481 AttributeValue::Vector(vec![1.0, 2.0, 3.0])
482 );
483 }
484
485 #[test]
486 fn should_convert_str_to_attribute_value() {
487 let value: AttributeValue = "test".into();
489
490 assert_eq!(value, AttributeValue::String("test".to_string()));
492 }
493
494 #[test]
495 fn should_convert_int_to_attribute_value() {
496 let value: AttributeValue = 42i64.into();
498
499 assert_eq!(value, AttributeValue::Int64(42));
501 }
502
503 #[test]
504 fn should_convert_attributes_to_map() {
505 let attributes = vec![
507 Attribute::new("name", AttributeValue::String("test".to_string())),
508 Attribute::new("count", AttributeValue::Int64(42)),
509 ];
510
511 let map = attributes_to_map(&attributes);
513
514 assert_eq!(map.len(), 2);
516 assert_eq!(
517 map.get("name"),
518 Some(&AttributeValue::String("test".to_string()))
519 );
520 assert_eq!(map.get("count"), Some(&AttributeValue::Int64(42)));
521 }
522}