1pub mod error;
29pub mod extensions;
30pub mod memory;
31pub mod stub;
32
33#[cfg(feature = "real-pg")]
34pub mod real_pg;
35
36#[cfg(feature = "hybrid-search")]
38pub mod hybrid_search;
39
40pub use error::VectorError;
41pub use extensions::{
42 AnnIndexDef, AnnIndexRegistry, AnnIndexType, BatchOpsExt, DimensionValidator, HnswParams,
43 IvfflatParams, MemoryBatchOps, SimilarityAlgorithms, VectorNormalizer, MAX_VECTOR_DIMENSION,
44 MIN_VECTOR_DIMENSION,
45};
46pub use memory::InMemoryVectorStore;
47pub use stub::StubVectorStore;
48
49#[cfg(feature = "real-pg")]
50pub use real_pg::{RealPgConfig, RealPgVectorStore};
51
52use async_trait::async_trait;
53use std::collections::HashMap;
54use std::str::FromStr;
55
56pub const MAX_TOP_K: usize = 10_000;
63
64pub fn validate_top_k(top_k: usize) -> Result<usize, VectorError> {
70 if top_k == 0 {
71 return Err(VectorError::TopKExceeded {
72 requested: top_k,
73 max: MAX_TOP_K,
74 });
75 }
76 if top_k > MAX_TOP_K {
77 return Err(VectorError::TopKExceeded {
78 requested: top_k,
79 max: MAX_TOP_K,
80 });
81 }
82 Ok(top_k)
83}
84
85#[derive(Debug, Clone)]
87pub struct VectorRecord {
88 pub id: String,
89 pub vector: Vec<f32>,
90 pub score: Option<f32>,
91 pub metadata: Option<HashMap<String, serde_json::Value>>,
92}
93
94impl VectorRecord {
95 pub fn new(id: impl Into<String>, vector: Vec<f32>) -> Self {
96 Self {
97 id: id.into(),
98 vector,
99 score: None,
100 metadata: None,
101 }
102 }
103
104 pub fn with_score(mut self, score: f32) -> Self {
105 self.score = Some(score);
106 self
107 }
108
109 pub fn with_metadata(mut self, metadata: HashMap<String, serde_json::Value>) -> Self {
110 self.metadata = Some(metadata);
111 self
112 }
113}
114
115#[derive(Debug, Clone)]
117pub struct SearchResult {
118 pub id: String,
119 pub score: f32,
120 pub vector: Vec<f32>,
121 pub text: Option<String>,
122 pub metadata: Option<HashMap<String, serde_json::Value>>,
123}
124
125impl SearchResult {
126 pub fn new(id: impl Into<String>, score: f32, vector: Vec<f32>) -> Self {
127 Self {
128 id: id.into(),
129 score,
130 vector,
131 text: None,
132 metadata: None,
133 }
134 }
135
136 pub fn with_text(mut self, text: impl Into<String>) -> Self {
137 self.text = Some(text.into());
138 self
139 }
140
141 pub fn with_metadata(mut self, metadata: HashMap<String, serde_json::Value>) -> Self {
142 self.metadata = Some(metadata);
143 self
144 }
145}
146
147#[derive(Debug, Clone, Copy, Default, PartialEq)]
149pub enum VectorMetric {
150 #[default]
151 Cosine,
152 Euclidean,
153 DotProduct,
154}
155
156impl VectorMetric {
157 pub fn pg_operator(&self) -> &'static str {
159 match self {
160 VectorMetric::Cosine => "<=>",
161 VectorMetric::Euclidean => "<->",
162 VectorMetric::DotProduct => "<#>",
163 }
164 }
165
166 pub fn as_str(&self) -> &'static str {
167 match self {
168 VectorMetric::Cosine => "cosine",
169 VectorMetric::Euclidean => "euclidean",
170 VectorMetric::DotProduct => "dotproduct",
171 }
172 }
173}
174
175impl FromStr for VectorMetric {
176 type Err = String;
177
178 fn from_str(s: &str) -> Result<Self, Self::Err> {
179 match s {
180 "cosine" => Ok(VectorMetric::Cosine),
181 "euclidean" => Ok(VectorMetric::Euclidean),
182 "dotproduct" => Ok(VectorMetric::DotProduct),
183 _ => Err(format!("unknown vector metric: {}", s)),
184 }
185 }
186}
187
188#[async_trait]
193pub trait PgVectorStore: Send + Sync {
194 async fn create_collection(
196 &self,
197 name: &str,
198 dimension: usize,
199 metric: Option<VectorMetric>,
200 ) -> Result<(), VectorError>;
201
202 async fn delete_collection(&self, name: &str) -> Result<(), VectorError>;
204
205 async fn insert(&self, collection: &str, records: Vec<VectorRecord>)
207 -> Result<(), VectorError>;
208
209 async fn search(
214 &self,
215 collection: &str,
216 query: &[f32],
217 top_k: usize,
218 ) -> Result<Vec<SearchResult>, VectorError>;
219
220 async fn get(&self, collection: &str, id: &str) -> Result<Option<VectorRecord>, VectorError>;
222
223 async fn delete(&self, collection: &str, ids: Vec<String>) -> Result<u64, VectorError>;
225
226 async fn count(&self, collection: &str) -> Result<usize, VectorError>;
228}