-
Notifications
You must be signed in to change notification settings - Fork 94
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
361 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
// To run this example execute: cargo run --example vector_store_qdrant --features qdrant | ||
|
||
#[cfg(feature = "qdrant")] | ||
use langchain_rust::{ | ||
embedding::openai::openai_embedder::OpenAiEmbedder, | ||
schemas::Document, | ||
vectorstore::qdrant::{QdrantClient, StoreBuilder}, | ||
vectorstore::VectorStore, | ||
}; | ||
#[cfg(feature = "qdrant")] | ||
use std::io::Write; | ||
|
||
#[cfg(feature = "qdrant")] | ||
#[tokio::main] | ||
async fn main() { | ||
// Initialize Embedder | ||
|
||
use langchain_rust::vectorstore::VecStoreOptions; | ||
|
||
// Requires OpenAI API key to be set in the environment variable OPENAI_API_KEY | ||
let embedder = OpenAiEmbedder::default(); | ||
|
||
// Initialize the qdrant_client::QdrantClient | ||
// Ensure Qdrant is running at localhost, with gRPC port at 6334 | ||
// docker run -p 6334:6334 qdrant/qdrant | ||
let client = QdrantClient::from_url("http://localhost:6334") | ||
.build() | ||
.unwrap(); | ||
|
||
let store = StoreBuilder::new() | ||
.embedder(embedder) | ||
.client(client) | ||
.collection_name("langchain-rs") | ||
.build() | ||
.await | ||
.unwrap(); | ||
|
||
// Add documents to the database | ||
let doc1 = Document::new( | ||
"langchain-rust is a port of the langchain python library to rust and was written in 2024.", | ||
); | ||
let doc2 = Document::new( | ||
"langchaingo is a port of the langchain python library to go language and was written in 2023." | ||
); | ||
let doc3 = Document::new( | ||
"Capital of United States of America (USA) is Washington D.C. and the capital of France is Paris." | ||
); | ||
let doc4 = Document::new("Capital of France is Paris."); | ||
|
||
store | ||
.add_documents(&vec![doc1, doc2, doc3, doc4], &VecStoreOptions::default()) | ||
.await | ||
.unwrap(); | ||
|
||
// Ask for user input | ||
print!("Query> "); | ||
std::io::stdout().flush().unwrap(); | ||
let mut query = String::new(); | ||
std::io::stdin().read_line(&mut query).unwrap(); | ||
|
||
let results = store | ||
.similarity_search(&query, 2, &VecStoreOptions::default()) | ||
.await | ||
.unwrap(); | ||
|
||
if results.is_empty() { | ||
println!("No results found."); | ||
return; | ||
} else { | ||
results.iter().for_each(|r| { | ||
println!("Document: {}", r.page_content); | ||
}); | ||
} | ||
} | ||
|
||
#[cfg(not(feature = "qdrant"))] | ||
fn main() { | ||
println!("This example requires the 'qdrant' feature to be enabled."); | ||
println!("Please run the command as follows:"); | ||
println!("cargo run --example vector_store_qdrant --features qdrant"); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,139 @@ | ||
use crate::embedding::Embedder; | ||
use crate::vectorstore::qdrant::Store; | ||
use qdrant_client::client::QdrantClient; | ||
use qdrant_client::qdrant::vectors_config::Config; | ||
use qdrant_client::qdrant::{CreateCollection, Distance, Filter, VectorParams, VectorsConfig}; | ||
use std::error::Error; | ||
use std::sync::Arc; | ||
|
||
pub struct StoreBuilder { | ||
client: Option<QdrantClient>, | ||
embedder: Option<Arc<dyn Embedder>>, | ||
collection_name: Option<String>, | ||
content_field: String, | ||
metadata_field: String, | ||
recreate_collection: bool, | ||
search_filter: Option<Filter>, | ||
} | ||
|
||
impl Default for StoreBuilder { | ||
fn default() -> Self { | ||
Self::new() | ||
} | ||
} | ||
|
||
impl StoreBuilder { | ||
/// Create a new StoreBuilder object with default values. | ||
pub fn new() -> Self { | ||
StoreBuilder { | ||
client: None, | ||
embedder: None, | ||
collection_name: None, | ||
search_filter: None, | ||
content_field: "page_content".to_string(), | ||
metadata_field: "metadata".to_string(), | ||
recreate_collection: false, | ||
} | ||
} | ||
|
||
/// An instance of `qdrant_client::QdrantClient` for the Store. REQUIRED. | ||
pub fn client(mut self, client: QdrantClient) -> Self { | ||
self.client = Some(client); | ||
self | ||
} | ||
|
||
/// Embeddings provider for the Store. REQUIRED. | ||
pub fn embedder<E: Embedder + 'static>(mut self, embedder: E) -> Self { | ||
self.embedder = Some(Arc::new(embedder)); | ||
self | ||
} | ||
|
||
/// Name of the collection in Qdrant. REQUIRED. | ||
/// It is recommended to create a collection in advance, with the required configurations. | ||
/// https://qdrant.tech/documentation/concepts/collections/#create-a-collection | ||
/// | ||
/// If the collection doesn't exist, it will be created with the embedding provider's dimension | ||
/// and Cosine similarity metric. | ||
pub fn collection_name(mut self, collection_name: &str) -> Self { | ||
self.collection_name = Some(collection_name.to_string()); | ||
self | ||
} | ||
|
||
/// Name of the field in the Qdrant point's payload that will store the metadata of the documents. | ||
/// Default: "metadata" | ||
pub fn metadata_field(mut self, metadata_field: &str) -> Self { | ||
self.metadata_field = metadata_field.to_string(); | ||
self | ||
} | ||
|
||
/// Name of the field in the Qdrant point's payload that will store the content of the documents. | ||
/// Default: "page_content" | ||
pub fn content_field(mut self, content_field: &str) -> Self { | ||
self.content_field = content_field.to_string(); | ||
self | ||
} | ||
|
||
/// If set to true, the collection will be deleted and recreated using | ||
/// the embedding provider's dimension and Cosine similarity metric. | ||
pub fn recreate_collection(mut self, recreate_collection: bool) -> Self { | ||
self.recreate_collection = recreate_collection; | ||
self | ||
} | ||
|
||
/// Filter to be applied to the search results. | ||
/// https://qdrant.tech/documentation/concepts/filtering/ | ||
/// Instance of use `qdrant_client::qdrant::Filter` | ||
pub fn search_filter(mut self, search_filter: Filter) -> Self { | ||
self.search_filter = Some(search_filter); | ||
self | ||
} | ||
|
||
/// Build the Store object. | ||
pub async fn build(mut self) -> Result<Store, Box<dyn Error>> { | ||
let client = self.client.take().ok_or("'client' is required")?; | ||
let embedder = self.embedder.take().ok_or("'embedder' is required")?; | ||
let collection_name = self | ||
.collection_name | ||
.take() | ||
.ok_or("'collection_name' is required")?; | ||
|
||
let collection_exists = client.collection_exists(&collection_name).await?; | ||
|
||
// Delete the collection if it exists and recreate_collection flag is set | ||
if collection_exists && self.recreate_collection { | ||
client.delete_collection(&collection_name).await?; | ||
} | ||
|
||
// Create the collection if it doesn't exist or recreate_collection flag is set | ||
if !collection_exists || self.recreate_collection { | ||
// Embed some text to get the dimension of the embeddings | ||
let embeddings = embedder | ||
.embed_query("Text to retrieve embeddings dimension") | ||
.await?; | ||
let embeddings_dimension = embeddings.len() as u64; | ||
|
||
client | ||
.create_collection(&CreateCollection { | ||
collection_name: collection_name.clone(), | ||
vectors_config: Some(VectorsConfig { | ||
config: Some(Config::Params(VectorParams { | ||
size: embeddings_dimension, | ||
distance: Distance::Cosine.into(), | ||
..Default::default() | ||
})), | ||
}), | ||
..Default::default() | ||
}) | ||
.await?; | ||
} | ||
|
||
Ok(Store { | ||
client, | ||
embedder, | ||
collection_name, | ||
search_filter: self.search_filter, | ||
content_field: self.content_field, | ||
metadata_field: self.metadata_field, | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
mod builder; | ||
mod qdrant; | ||
|
||
pub use builder::*; | ||
pub use qdrant::*; |
Oops, something went wrong.