qail_qdrant/
point.rs

1//! Point and payload types for Qdrant.
2
3use serde::{Deserialize, Serialize};
4use std::collections::HashMap;
5
6/// Point ID - either UUID string or integer.
7#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
8pub enum PointId {
9    Uuid(String),
10    Num(u64),
11}
12
13impl From<&str> for PointId {
14    fn from(s: &str) -> Self {
15        PointId::Uuid(s.to_string())
16    }
17}
18
19impl From<String> for PointId {
20    fn from(s: String) -> Self {
21        PointId::Uuid(s)
22    }
23}
24
25impl From<u64> for PointId {
26    fn from(n: u64) -> Self {
27        PointId::Num(n)
28    }
29}
30
31/// Payload value types.
32#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
33#[serde(untagged)]
34pub enum PayloadValue {
35    String(String),
36    Integer(i64),
37    Float(f64),
38    Bool(bool),
39    List(Vec<PayloadValue>),
40    Object(HashMap<String, PayloadValue>),
41    Null,
42}
43
44/// Payload - key-value metadata attached to points.
45pub type Payload = HashMap<String, PayloadValue>;
46
47/// A point in Qdrant - vector + payload + id.
48#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
49pub struct Point {
50    pub id: PointId,
51    pub vector: Vec<f32>,
52    #[serde(default)]
53    pub payload: Payload,
54}
55
56impl Point {
57    /// Create a new point with a string/UUID ID.
58    pub fn new(id: impl Into<PointId>, vector: Vec<f32>) -> Self {
59        Self {
60            id: id.into(),
61            vector,
62            payload: HashMap::new(),
63        }
64    }
65
66    /// Create a new point with a numeric ID.
67    pub fn new_num(id: u64, vector: Vec<f32>) -> Self {
68        Self {
69            id: PointId::Num(id),
70            vector,
71            payload: HashMap::new(),
72        }
73    }
74
75    /// Add payload field.
76    pub fn with_payload(mut self, key: impl Into<String>, value: impl Into<PayloadValue>) -> Self {
77        self.payload.insert(key.into(), value.into());
78        self
79    }
80}
81
82/// Sparse vector - only non-zero indices and their values.
83#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
84pub struct SparseVector {
85    /// Indices of non-zero elements.
86    pub indices: Vec<u32>,
87    /// Values at those indices.
88    pub values: Vec<f32>,
89}
90
91impl SparseVector {
92    /// Create a sparse vector from indices and values.
93    pub fn new(indices: Vec<u32>, values: Vec<f32>) -> Self {
94        Self { indices, values }
95    }
96
97    /// Create from a dense vector (only keeps non-zero elements).
98    pub fn from_dense(dense: &[f32], threshold: f32) -> Self {
99        let mut indices = Vec::new();
100        let mut values = Vec::new();
101        for (i, &v) in dense.iter().enumerate() {
102            if v.abs() > threshold {
103                indices.push(i as u32);
104                values.push(v);
105            }
106        }
107        Self { indices, values }
108    }
109}
110
111/// Vector type that can be named or anonymous.
112#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
113#[serde(untagged)]
114pub enum VectorData {
115    /// Single unnamed vector.
116    Single(Vec<f32>),
117    /// Named vectors (for multi-vector collections).
118    Named(HashMap<String, Vec<f32>>),
119    /// Sparse vector.
120    Sparse { indices: Vec<u32>, values: Vec<f32> },
121}
122
123/// A point with named vector support (for multi-vector collections).
124#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
125pub struct MultiVectorPoint {
126    pub id: PointId,
127    /// Named vectors - key is vector name, value is the embedding.
128    pub vectors: HashMap<String, Vec<f32>>,
129    #[serde(default)]
130    pub payload: Payload,
131}
132
133impl MultiVectorPoint {
134    /// Create a new multi-vector point.
135    pub fn new(id: impl Into<PointId>) -> Self {
136        Self {
137            id: id.into(),
138            vectors: HashMap::new(),
139            payload: HashMap::new(),
140        }
141    }
142
143    /// Add a named vector.
144    pub fn with_vector(mut self, name: impl Into<String>, vector: Vec<f32>) -> Self {
145        self.vectors.insert(name.into(), vector);
146        self
147    }
148
149    /// Add payload field.
150    pub fn with_payload(mut self, key: impl Into<String>, value: impl Into<PayloadValue>) -> Self {
151        self.payload.insert(key.into(), value.into());
152        self
153    }
154}
155
156/// Search result - point with similarity score.
157#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
158pub struct ScoredPoint {
159    pub id: PointId,
160    pub score: f32,
161    #[serde(default)]
162    pub payload: Payload,
163    #[serde(default)]
164    pub vector: Option<Vec<f32>>,
165}
166
167// Convenient From implementations for PayloadValue
168impl From<String> for PayloadValue {
169    fn from(s: String) -> Self {
170        PayloadValue::String(s)
171    }
172}
173
174impl From<&str> for PayloadValue {
175    fn from(s: &str) -> Self {
176        PayloadValue::String(s.to_string())
177    }
178}
179
180impl From<i64> for PayloadValue {
181    fn from(n: i64) -> Self {
182        PayloadValue::Integer(n)
183    }
184}
185
186impl From<f64> for PayloadValue {
187    fn from(n: f64) -> Self {
188        PayloadValue::Float(n)
189    }
190}
191
192impl From<bool> for PayloadValue {
193    fn from(b: bool) -> Self {
194        PayloadValue::Bool(b)
195    }
196}