SurrealDB
The rig-surrealdb crate implements Rig’s VectorStoreIndex trait on top of SurrealDB, using SurrealDB’s built-in vector functions (for example vector::similarity::cosine). It works with an in-memory instance for local development or a remote instance in production, and supports several distance metrics.
Add the crate to your project:
cargo add rig-surrealdbMinimal example
Section titled “Minimal example”Connect to SurrealDB, embed a set of documents, insert them, then run a similarity search. top_n takes a VectorSearchRequest and deserializes each hit into your type.
use rig::client::{EmbeddingsClient, ProviderClient};use rig::embeddings::EmbeddingsBuilder;use rig::providers::openai;use rig::vector_store::{InsertDocuments, VectorSearchRequest, VectorStoreIndex};use rig::Embed;use rig_surrealdb::{Mem, SurrealVectorStore};use serde::{Deserialize, Serialize};use surrealdb::Surreal;
// Embeds the `definition` field for similarity search. `definition` is skipped// during serialization since we only use it to generate embeddings.#[derive(Embed, Serialize, Deserialize, Clone, Debug, Eq, PartialEq, Default)]struct WordDefinition { word: String, #[serde(skip)] #[embed] definition: String,}
#[tokio::main]async fn main() -> Result<(), anyhow::Error> { let openai_client = openai::Client::from_env()?; let model = openai_client.embedding_model(openai::TEXT_EMBEDDING_3_SMALL);
// In-memory instance; swap `Mem` for a remote engine in production. let surreal = Surreal::new::<Mem>(()).await?; surreal.use_ns("example").use_db("example").await?;
let words = vec![ WordDefinition { word: "flurbo".to_string(), definition: "A fictional currency from Rick and Morty.".to_string(), }, WordDefinition { word: "glarb-glarb".to_string(), definition: "A creature from the marshlands of Glibbo.".to_string(), }, ];
let documents = EmbeddingsBuilder::new(model.clone()) .documents(words)? .build() .await?;
let vector_store = SurrealVectorStore::with_defaults(model, surreal); vector_store.insert_documents(documents).await?;
let req = VectorSearchRequest::builder() .query("weird alien creature") .samples(2) .build();
let results = vector_store.top_n::<WordDefinition>(req).await?; for (distance, _id, doc) in results { println!("Distance: {distance:.3}, Word: {}", doc.word); }
Ok(())}How it works
Section titled “How it works”SurrealVectorStore::with_defaults(model, surreal)builds a store over the given SurrealDB connection using the default table and cosine distance.insert_documentsembeds and inserts documents into the vector index.top_n::<T>(request)embeds the query, runs the search, and deserializes each match intoTas(distance, id, T).
Score thresholds
Section titled “Score thresholds”Add a threshold to the request to drop weak matches. Thresholds are interpreted against the store’s distance function:
let req = VectorSearchRequest::builder() .query("weird alien creature") .samples(1) .threshold(0.5) .build();
let results = vector_store.top_n::<WordDefinition>(req).await?;Distance functions
Section titled “Distance functions”The default is cosine. To customize the table name and distance metric, construct the store directly:
use rig_surrealdb::SurrealDistanceFunction;
let custom_store = SurrealVectorStore::new( model, surreal, Some("my_table".into()), SurrealDistanceFunction::Jaccard,);Available options:
Cosine(default)EuclideanHammingJaccardKnn
See also
Section titled “See also”- Vector Stores overview — shared
VectorStoreIndex/VectorSearchRequest/EmbeddingsBuilderconcepts. - Vector Stores & RAG — how retrieval fits into an agent.
rig-surrealdbexamples and the SurrealDB documentation.
