1#![warn(missing_docs)]
2pub mod chromadb;
8pub mod chunked_vector_store;
9pub mod document_store;
10mod file_store;
11pub mod lancedb;
12mod memory;
13pub mod neo4j;
14mod provider;
15
16#[cfg(feature = "mongodb-persistence")]
17mod mongo_document_store;
18
19#[cfg(feature = "qdrant-integration")]
20mod qdrant;
21
22#[cfg(feature = "redis-storage")]
23pub mod redis_store;
24
25#[cfg(feature = "sqlite-storage")]
26pub mod sqlite_store;
27
28#[cfg(feature = "pgvector-storage")]
29pub mod pgvector;
30
31pub mod pinecone;
32
33pub use chunked_vector_store::ChunkedVectorStore;
34pub use document_store::{
35 ChunkedDocumentStore, ChunkedDocumentStoreTrait, DocumentStore, InMemoryChunkedDocumentStore,
36 InMemoryDocumentStore,
37};
38pub use file_store::FileVectorStore;
39pub use lancedb::{LanceDBConfig, LanceDBVectorStore};
40pub use memory::InMemoryVectorStore;
41pub use neo4j::{Neo4jConfig, Neo4jVectorStore};
42pub use pinecone::PineconeStore;
43pub use provider::{VectorStoreBuilder, VectorStoreProvider, VectorStoreType};
44
45#[cfg(feature = "mongodb-persistence")]
46pub use mongo_document_store::{MongoChunkedDocumentStore, MongoStoreConfig};
47
48#[cfg(feature = "qdrant-integration")]
49pub use qdrant::{QdrantConfig, QdrantDistance, QdrantVectorStore};
50
51pub use chromadb::{ChromaDBConfig, ChromaDBVectorStore};
52
53#[cfg(feature = "redis-storage")]
54pub use redis_store::{RedisDocumentStore, RedisStoreConfig};
55
56#[cfg(feature = "sqlite-storage")]
57pub use sqlite_store::{SQLiteDocumentStore, SQLiteStoreConfig};
58
59use async_trait::async_trait;
60
61pub use lc_shared::document::{ChunkDocument, Document, SearchResult, VectorDocument};
63
64pub use lc_core::math::cosine_similarity;
66
67#[derive(Debug, thiserror::Error)]
69#[non_exhaustive]
70pub enum VectorStoreError {
71 #[error("Document not found: {0}")]
73 DocumentNotFound(String),
74
75 #[error("Embedding error: {0}")]
77 EmbeddingError(String),
78
79 #[error("Storage error: {0}")]
81 StorageError(String),
82
83 #[error("Connection error: {0}")]
85 ConnectionError(String),
86
87 #[error("Configuration error: {0}")]
89 ConfigError(String),
90}
91
92#[async_trait]
94pub trait VectorStore: Send + Sync {
95 async fn add_documents(
104 &self,
105 documents: Vec<Document>,
106 embeddings: Vec<Vec<f32>>,
107 ) -> Result<Vec<String>, VectorStoreError>;
108
109 async fn similarity_search(
118 &self,
119 query_embedding: &[f32],
120 k: usize,
121 ) -> Result<Vec<SearchResult>, VectorStoreError>;
122
123 fn embed_query(&self) -> Option<&dyn Embeddings> {
130 None
131 }
132
133 async fn similarity_search_text(
139 &self,
140 query: &str,
141 k: usize,
142 ) -> Result<Vec<SearchResult>, VectorStoreError> {
143 let Some(embeddings) = self.embed_query() else {
144 return Err(VectorStoreError::EmbeddingError(
145 "this vector store has no embedder configured; cannot auto-vectorize the query \
146 text; call similarity_search with a query vector instead"
147 .to_string(),
148 ));
149 };
150 let query_embedding = embeddings
151 .embed_query(query)
152 .await
153 .map_err(|e| VectorStoreError::EmbeddingError(e.to_string()))?;
154 self.similarity_search(&query_embedding, k).await
155 }
156
157 async fn similarity_search_with_min_score(
166 &self,
167 query_embedding: &[f32],
168 k: usize,
169 min_score: Option<f32>,
170 ) -> Result<Vec<SearchResult>, VectorStoreError> {
171 let results = self.similarity_search(query_embedding, k).await?;
172 match min_score {
173 Some(threshold) => Ok(results
174 .into_iter()
175 .filter(|r| r.score >= threshold)
176 .collect()),
177 None => Ok(results),
178 }
179 }
180
181 async fn get_document(&self, id: &str) -> Result<Option<Document>, VectorStoreError>;
183
184 async fn get_embedding(&self, id: &str) -> Result<Option<Vec<f32>>, VectorStoreError>;
186
187 async fn delete_document(&self, id: &str) -> Result<(), VectorStoreError>;
189
190 async fn count(&self) -> usize;
192
193 async fn clear(&self) -> Result<(), VectorStoreError>;
195}
196
197pub use lc_embeddings::{EmbeddingError, Embeddings};
202
203#[cfg(test)]
204mod tests {
205 use super::*;
206
207 #[test]
208 fn test_document_creation() {
209 let doc = Document::new("Hello, world!")
210 .with_metadata("source", "test")
211 .with_id("doc-1");
212
213 assert_eq!(doc.content, "Hello, world!");
214 assert_eq!(
215 doc.metadata.get("source"),
216 Some(&serde_json::Value::String("test".to_string()))
217 );
218 assert_eq!(doc.id, Some("doc-1".to_string()));
219 }
220
221 #[test]
222 fn test_document_page_content() {
223 let doc = Document::new("Test content");
224 assert_eq!(doc.page_content(), "Test content");
225 }
226}