Qdrant
The rig-qdrant crate implements Rig’s VectorStoreIndex trait on top of Qdrant, a fast vector search database written in Rust. Use it when you want a dedicated, filterable vector store that scales beyond the in-memory store.
Add the crate to your project:
cargo add rig-qdrantYou will also need a running Qdrant instance. The quickest way is Docker:
docker run -p 6333:6333 -p 6334:6334 qdrant/qdrantMinimal example
Section titled “Minimal example”Create a collection, embed some documents, insert them, then search. The vector dimension of the collection must match your embedding model (text-embedding-3-small and text-embedding-ada-002 both produce 1536-dimensional vectors).
use qdrant_client::{ Qdrant, qdrant::{CreateCollectionBuilder, Distance, QueryPointsBuilder, VectorParamsBuilder},};use rig::client::{EmbeddingsClient, ProviderClient};use rig::providers::openai;use rig::embeddings::EmbeddingsBuilder;use rig::vector_store::{InsertDocuments, VectorSearchRequest, VectorStoreIndex};use rig::Embed;use rig_qdrant::QdrantVectorStore;use serde::{Deserialize, Serialize};
const COLLECTION_NAME: &str = "rig-collection";
#[derive(Embed, Serialize, Deserialize, Debug)]struct Word { id: String, #[embed] definition: String,}
#[tokio::main]async fn main() -> Result<(), anyhow::Error> { let client = Qdrant::from_url("http://localhost:6334").build()?;
// Create a 1536-dimension collection if it doesn't already exist. if !client.collection_exists(COLLECTION_NAME).await? { client .create_collection( CreateCollectionBuilder::new(COLLECTION_NAME) .vectors_config(VectorParamsBuilder::new(1536, Distance::Cosine)), ) .await?; }
let openai_client = openai::Client::from_env()?; let model = openai_client.embedding_model(openai::TEXT_EMBEDDING_3_SMALL);
let documents = EmbeddingsBuilder::new(model.clone()) .document(Word { id: "doc0".to_string(), definition: "A flurbo is a green alien that lives on cold planets.".to_string(), })? .document(Word { id: "doc1".to_string(), definition: "A linglingdong is a term used to describe humans.".to_string(), })? .build() .await?;
// Build the vector store over the collection. let query_params = QueryPointsBuilder::new(COLLECTION_NAME).with_payload(true); let vector_store = QdrantVectorStore::new(client, model, query_params.build());
// Insert the embedded documents (InsertDocuments trait). vector_store.insert_documents(documents).await?;
// Search. let req = VectorSearchRequest::builder() .query("What is a linglingdong?") .samples(1) .build();
let results = vector_store.top_n::<Word>(req).await?; println!("{results:#?}");
Ok(())}How it works
Section titled “How it works”QdrantVectorStore::new(client, model, query_params)wraps a Qdrant client, an embedding model, and aQueryPointsBuilderdescribing how points are queried. Enable.with_payload(true)so the stored document payloads come back with each hit.insert_documentsembeds and upserts documents into the collection (via theInsertDocumentstrait).top_n::<T>(request)embeds the query, runs the search, and deserializes each payload intoT.
Filtering
Section titled “Filtering”Qdrant supports server-side filtering. VectorSearchRequest is generic over its filter type, so a store-specific filter parameterizes the request — here VectorSearchRequest::<QdrantFilter> builds a typed request that constrains results to matching payloads:
use rig_qdrant::QdrantFilter;
let req = VectorSearchRequest::<QdrantFilter>::builder() .query("What is a linglingdong?") .samples(1) .filter(QdrantFilter::eq("id", serde_json::json!("doc1"))) .build();
let results = vector_store.top_n::<Word>(req).await?;See also
Section titled “See also”- Vector Stores overview — shared
VectorStoreIndex/VectorSearchRequest/EmbeddingsBuilderconcepts. - Vector Stores & RAG — how retrieval fits into an agent.
rig-qdrantexamples and the Qdrant collections docs.
