# pgvector-rust [pgvector](https://github.com/pgvector/pgvector) support for Rust Supports [Rust-Postgres](https://github.com/sfackler/rust-postgres), [SQLx](https://github.com/launchbadge/sqlx), and [Diesel](https://github.com/diesel-rs/diesel) [![Build Status](https://github.com/pgvector/pgvector-rust/actions/workflows/build.yml/badge.svg)](https://github.com/pgvector/pgvector-rust/actions) ## Getting Started Follow the instructions for your database library: - [Rust-Postgres](#rust-postgres) - [SQLx](#sqlx) - [Diesel](#diesel) Or check out some examples: - [Embeddings](https://github.com/pgvector/pgvector-rust/blob/master/examples/openai/src/main.rs) with OpenAI - [Binary embeddings](https://github.com/pgvector/pgvector-rust/blob/master/examples/cohere/src/main.rs) with Cohere - [Sentence embeddings](https://github.com/pgvector/pgvector-rust/blob/master/examples/candle/src/main.rs) with Candle - [Hybrid search](https://github.com/pgvector/pgvector-rust/blob/master/examples/hybrid_search/src/main.rs) with Candle (Reciprocal Rank Fusion) - [Recommendations](https://github.com/pgvector/pgvector-rust/blob/master/examples/disco/src/main.rs) with Disco - [Bulk loading](https://github.com/pgvector/pgvector-rust/blob/master/examples/loading/src/main.rs) with `COPY` ## Rust-Postgres Add this line to your application’s `Cargo.toml` under `[dependencies]`: ```toml pgvector = { version = "0.4", features = ["postgres"] } ``` Enable the extension ```rust client.execute("CREATE EXTENSION IF NOT EXISTS vector", &[])?; ``` Create a table ```rust client.execute("CREATE TABLE items (id bigserial PRIMARY KEY, embedding vector(3))", &[])?; ``` Create a vector from a `Vec` ```rust use pgvector::Vector; let embedding = Vector::from(vec![1.0, 2.0, 3.0]); ``` Insert a vector ```rust client.execute("INSERT INTO items (embedding) VALUES ($1)", &[&embedding])?; ``` Get the nearest neighbor ```rust let row = client.query_one( "SELECT * FROM items ORDER BY embedding <-> $1 LIMIT 1", &[&embedding], )?; ``` Retrieve a vector ```rust let row = client.query_one("SELECT embedding FROM items LIMIT 1", &[])?; let embedding: Vector = row.get(0); ``` Use `Option` if the value could be `NULL` ```rust let embedding: Option = row.get(0); ``` ## SQLx Add this line to your application’s `Cargo.toml` under `[dependencies]`: ```toml pgvector = { version = "0.4", features = ["sqlx"] } ``` For SQLx < 0.8, use `version = "0.3"` and [this readme](https://github.com/pgvector/pgvector-rust/blob/v0.3.4/README.md). Enable the extension ```rust sqlx::query("CREATE EXTENSION IF NOT EXISTS vector") .execute(&pool) .await?; ``` Create a table ```rust sqlx::query("CREATE TABLE items (id bigserial PRIMARY KEY, embedding vector(3))") .execute(&pool) .await?; ``` Create a vector from a `Vec` ```rust use pgvector::Vector; let embedding = Vector::from(vec![1.0, 2.0, 3.0]); ``` Insert a vector ```rust sqlx::query("INSERT INTO items (embedding) VALUES ($1)") .bind(embedding) .execute(&pool) .await?; ``` Get the nearest neighbors ```rust let rows = sqlx::query("SELECT * FROM items ORDER BY embedding <-> $1 LIMIT 1") .bind(embedding) .fetch_all(&pool) .await?; ``` Retrieve a vector ```rust let row = sqlx::query("SELECT embedding FROM items LIMIT 1").fetch_one(&pool).await?; let embedding: Vector = row.try_get("embedding")?; ``` ## Diesel Add this line to your application’s `Cargo.toml` under `[dependencies]`: ```toml pgvector = { version = "0.4", features = ["diesel"] } ``` And update your application’s `diesel.toml` under `[print_schema]`: ```toml import_types = ["diesel::sql_types::*", "pgvector::sql_types::*"] generate_missing_sql_type_definitions = false ``` Create a migration ```sh diesel migration generate create_vector_extension ``` with `up.sql`: ```sql CREATE EXTENSION vector ``` and `down.sql`: ```sql DROP EXTENSION vector ``` Run the migration ```sql diesel migration run ``` You can now use the `vector` type in future migrations ```sql CREATE TABLE items ( id SERIAL PRIMARY KEY, embedding VECTOR(3) ) ``` For models, use: ```rust use pgvector::Vector; #[derive(Queryable)] #[diesel(table_name = items)] pub struct Item { pub id: i32, pub embedding: Option, } #[derive(Insertable)] #[diesel(table_name = items)] pub struct NewItem { pub embedding: Option, } ``` Create a vector from a `Vec` ```rust let embedding = Vector::from(vec![1.0, 2.0, 3.0]); ``` Insert a vector ```rust let new_item = NewItem { embedding: Some(embedding) }; diesel::insert_into(items::table) .values(&new_item) .get_result::(&mut conn)?; ``` Get the nearest neighbors ```rust use pgvector::VectorExpressionMethods; let neighbors = items::table .order(items::embedding.l2_distance(embedding)) .limit(5) .load::(&mut conn)?; ``` Also supports `max_inner_product`, `cosine_distance`, `l1_distance`, `hamming_distance`, and `jaccard_distance` Get the distances ```rust let distances = items::table .select(items::embedding.l2_distance(embedding)) .load::>(&mut conn)?; ``` Add an approximate index in a migration ```sql CREATE INDEX my_index ON items USING hnsw (embedding vector_l2_ops) -- or CREATE INDEX my_index ON items USING ivfflat (embedding vector_l2_ops) WITH (lists = 100) ``` Use `vector_ip_ops` for inner product and `vector_cosine_ops` for cosine distance ## Serialization Use the `serde` feature to enable serialization ## Half Vectors Use the `halfvec` feature to enable half vectors ## Reference Convert a vector to a `Vec` ```rust let f32_vec: Vec = vec.into(); ``` Get a slice ```rust let slice = vec.as_slice(); ``` ## History View the [changelog](https://github.com/pgvector/pgvector-rust/blob/master/CHANGELOG.md) ## Contributing Everyone is encouraged to help improve this project. Here are a few ways you can help: - [Report bugs](https://github.com/pgvector/pgvector-rust/issues) - Fix bugs and [submit pull requests](https://github.com/pgvector/pgvector-rust/pulls) - Write, clarify, or fix documentation - Suggest or add new features To get started with development: ```sh git clone https://github.com/pgvector/pgvector-rust.git cd pgvector-rust createdb pgvector_rust_test cargo test --all-features ```