Skip to content
Get Started

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:

Terminal window
cargo add rig-qdrant

You will also need a running Qdrant instance. The quickest way is Docker:

Terminal window
docker run -p 6333:6333 -p 6334:6334 qdrant/qdrant

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(())
}
  • QdrantVectorStore::new(client, model, query_params) wraps a Qdrant client, an embedding model, and a QueryPointsBuilder describing how points are queried. Enable .with_payload(true) so the stored document payloads come back with each hit.
  • insert_documents embeds and upserts documents into the collection (via the InsertDocuments trait).
  • top_n::<T>(request) embeds the query, runs the search, and deserializes each payload into T.

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?;