In-Memory Vector Store
InMemoryVectorStore is Rig’s default vector store, included in rig. It keeps documents and embeddings in RAM and performs cosine-similarity search with no external dependencies — ideal for development, tests, and small-scale applications.
Quick start
Section titled “Quick start”use rig::client::{ProviderClient, EmbeddingsClient};use rig::providers::openai;use rig::embeddings::EmbeddingsBuilder;use rig::vector_store::in_memory_store::InMemoryVectorStore;use rig::vector_store::{VectorStoreIndex, VectorSearchRequest};use rig::Embed;use serde::{Deserialize, Serialize};
#[derive(Embed, Clone, Serialize, Deserialize, Debug, PartialEq, Eq)]struct WordDefinition { id: String, #[embed] definition: String,}
#[tokio::main]async fn main() -> Result<(), anyhow::Error> { let openai = openai::Client::from_env()?; let model = openai.embedding_model(openai::TEXT_EMBEDDING_3_SMALL);
let documents = vec![ WordDefinition { id: "doc0".into(), definition: "First document content".into() }, WordDefinition { id: "doc1".into(), definition: "Second document content".into() }, ];
let embeddings = EmbeddingsBuilder::new(model.clone()) .documents(documents)? .build() .await?;
// Build the store, then create an index over it with the query model. let index = InMemoryVectorStore::from_documents(embeddings).index(model);
let req = VectorSearchRequest::builder() .query("search query") .samples(5) .build();
let results = index.top_n::<WordDefinition>(req).await?; println!("{results:#?}");
Ok(())}How it stores documents
Section titled “How it stores documents”Internally the store maps a string id to a (document, embeddings) pair:
pub struct InMemoryVectorStore<D: Serialize> { embeddings: HashMap<String, (D, OneOrMany<Embedding>)>,}- Key — the document id (auto-generated or supplied by you).
- Value — the serializable document
Dplus itsOneOrMany<Embedding>.
OneOrMany lets each document carry either a single embedding or several (for example one per chunk). On search, the store computes cosine similarity between the query and every stored embedding, ranks each document by its best-matching embedding, and uses a binary heap to keep the top-N results.
Adding documents
Section titled “Adding documents”Besides passing EmbeddingsBuilder output to add_documents (the shared InsertDocuments trait), the in-memory store has three convenience constructors that insert on creation:
// 1. Auto-generated idslet store = InMemoryVectorStore::from_documents(vec![ (doc1, embedding1), (doc2, embedding2),]);
// 2. Explicit idslet store = InMemoryVectorStore::from_documents_with_ids(vec![ ("custom_id_1", doc1, embedding1), ("custom_id_2", doc2, embedding2),]);
// 3. Ids derived from each documentlet store = InMemoryVectorStore::from_documents_with_id_f( documents, |doc| format!("doc_{}", doc.id),);Each returns a store; call .index(model) on it to get a queryable VectorStoreIndex.
Index strategies
Section titled “Index strategies”The store’s search strategy is configurable via the IndexStrategy enum:
- Brute-force (default) — linear scan with cosine similarity.
O(n)per query; best for small datasets. - LSH (Locality-Sensitive Hashing) — approximate nearest-neighbor search via the
rig::vector_store::lshmodule. Consider it for datasets beyond a few thousand documents.
Using it as an agent tool
Section titled “Using it as an agent tool”Like every VectorStoreIndex, an in-memory index implements Tool, so you can attach it to an agent directly:
let agent = openai.agent("gpt-5.5") .preamble("You can search a knowledge base.") .tool(index) .build();Considerations
Section titled “Considerations”Memory — all documents and embeddings live in RAM, so usage scales linearly with document count and embedding dimensions. Large arrays (over ~400 elements) are pruned automatically to keep the footprint down.
Persistence — none. The store is rebuilt every run and lives on a single machine.
Concurrency — the store is safe for concurrent reads but needs exclusive access for writes. It implements Clone, Send, and Sync; for shared writes, wrap it in a synchronization primitive such as Arc<RwLock<InMemoryVectorStore<_>>>.
When to move on
Section titled “When to move on”The in-memory store is best for development and small workloads. For persistence, larger datasets, and richer filtering, switch to a database-backed store — the query and embedding code stays the same. See the comparison table and store directory.
See also
Section titled “See also”- Vector Stores overview — traits,
VectorSearchRequest, and filters shared across all stores. - Vector Stores & RAG — using retrieval in a RAG pipeline.
