1#![warn(missing_docs)]
2pub mod chromadb;
8pub mod chunked_vector_store;
9pub mod document_store;
10mod file_store;
11pub mod filter;
12pub mod lancedb;
13mod memory;
14pub mod neo4j;
15mod provider;
16
17#[cfg(feature = "mongodb-persistence")]
18mod mongo_document_store;
19
20#[cfg(feature = "qdrant-integration")]
21mod qdrant;
22
23#[cfg(feature = "redis-storage")]
24pub mod redis_store;
25
26#[cfg(feature = "sqlite-storage")]
27pub mod sqlite_store;
28
29#[cfg(feature = "pgvector-storage")]
30pub mod pgvector;
31
32pub mod pinecone;
33
34pub use chunked_vector_store::ChunkedVectorStore;
35pub use document_store::{
36 ChunkedDocumentStore, ChunkedDocumentStoreTrait, DocumentStore, InMemoryChunkedDocumentStore,
37 InMemoryDocumentStore,
38};
39pub use file_store::FileVectorStore;
40pub use filter::{FilterOp, MetadataFilter};
41pub use lancedb::{LanceDBConfig, LanceDBVectorStore};
42pub use memory::InMemoryVectorStore;
43pub use neo4j::{Neo4jConfig, Neo4jVectorStore};
44pub use pinecone::PineconeStore;
45pub use provider::{VectorStoreBuilder, VectorStoreProvider, VectorStoreType};
46
47#[cfg(feature = "mongodb-persistence")]
48pub use mongo_document_store::{MongoChunkedDocumentStore, MongoStoreConfig};
49
50#[cfg(feature = "qdrant-integration")]
51pub use qdrant::{QdrantConfig, QdrantDistance, QdrantVectorStore};
52
53pub use chromadb::{ChromaDBConfig, ChromaDBVectorStore};
54
55#[cfg(feature = "redis-storage")]
56pub use redis_store::{RedisDocumentStore, RedisStoreConfig};
57
58#[cfg(feature = "sqlite-storage")]
59pub use sqlite_store::{SQLiteDocumentStore, SQLiteStoreConfig};
60
61#[cfg(feature = "pgvector-storage")]
62pub use pgvector::{build_filter_sql, FilterBinding, FilterSql, PGVectorConfig, PGVectorStore};
63
64use async_trait::async_trait;
65
66pub use lc_shared::document::{ChunkDocument, Document, SearchResult, VectorDocument};
68
69pub use lc_core::math::cosine_similarity;
71
72#[derive(Debug, thiserror::Error)]
74#[non_exhaustive]
75pub enum VectorStoreError {
76 #[error("Document not found: {0}")]
78 DocumentNotFound(String),
79
80 #[error("Embedding error: {0}")]
82 EmbeddingError(String),
83
84 #[error("Storage error: {0}")]
86 StorageError(String),
87
88 #[error("Connection error: {0}")]
90 ConnectionError(String),
91
92 #[error("Configuration error: {0}")]
94 ConfigError(String),
95
96 #[error("Metadata filter not supported: {0}")]
98 UnsupportedFilter(String),
99}
100
101#[async_trait]
103pub trait VectorStore: Send + Sync {
104 async fn add_documents(
113 &self,
114 documents: Vec<Document>,
115 embeddings: Vec<Vec<f32>>,
116 ) -> Result<Vec<String>, VectorStoreError>;
117
118 async fn similarity_search(
127 &self,
128 query_embedding: &[f32],
129 k: usize,
130 ) -> Result<Vec<SearchResult>, VectorStoreError>;
131
132 fn embed_query(&self) -> Option<&dyn Embeddings> {
140 None
141 }
142
143 async fn similarity_search_text(
149 &self,
150 query: &str,
151 k: usize,
152 ) -> Result<Vec<SearchResult>, VectorStoreError> {
153 let Some(embeddings) = self.embed_query() else {
154 return Err(VectorStoreError::EmbeddingError(
155 "this vector store has no embedder configured; cannot auto-vectorize the query \
156 text; call similarity_search with a query vector instead"
157 .to_string(),
158 ));
159 };
160 let query_embedding = embeddings
161 .embed_query(query)
162 .await
163 .map_err(|e| VectorStoreError::EmbeddingError(e.to_string()))?;
164 self.similarity_search(&query_embedding, k).await
165 }
166
167 async fn similarity_search_with_filter(
178 &self,
179 query_embedding: &[f32],
180 k: usize,
181 filter: Option<&MetadataFilter>,
182 ) -> Result<Vec<SearchResult>, VectorStoreError> {
183 match filter {
184 None => self.similarity_search(query_embedding, k).await,
185 Some(_) => Err(VectorStoreError::UnsupportedFilter(
186 "this vector store does not support metadata filtering; pass filter: None or \
187 switch to a store that implements similarity_search_with_filter"
188 .to_string(),
189 )),
190 }
191 }
192
193 async fn similarity_search_with_min_score(
204 &self,
205 query_embedding: &[f32],
206 k: usize,
207 min_score: Option<f32>,
208 ) -> Result<Vec<SearchResult>, VectorStoreError> {
209 let results = self.similarity_search(query_embedding, k).await?;
210 match min_score {
211 Some(threshold) => Ok(results
212 .into_iter()
213 .filter(|r| r.score >= threshold)
214 .collect()),
215 None => Ok(results),
216 }
217 }
218
219 async fn get_document(&self, id: &str) -> Result<Option<Document>, VectorStoreError>;
221
222 async fn get_embedding(&self, id: &str) -> Result<Option<Vec<f32>>, VectorStoreError>;
224
225 async fn delete_document(&self, id: &str) -> Result<(), VectorStoreError>;
227
228 async fn count(&self) -> usize;
230
231 async fn clear(&self) -> Result<(), VectorStoreError>;
233}
234
235pub use lc_embeddings::{EmbeddingError, Embeddings};
240
241#[cfg(test)]
242mod tests {
243 use super::*;
244
245 #[test]
246 fn test_document_creation() {
247 let doc = Document::new("Hello, world!")
248 .with_metadata("source", "test")
249 .with_id("doc-1");
250
251 assert_eq!(doc.content, "Hello, world!");
252 assert_eq!(
253 doc.metadata.get("source"),
254 Some(&serde_json::Value::String("test".to_string()))
255 );
256 assert_eq!(doc.id, Some("doc-1".to_string()));
257 }
258
259 #[test]
260 fn test_document_page_content() {
261 let doc = Document::new("Test content");
262 assert_eq!(doc.page_content(), "Test content");
263 }
264}