pgvector support for .NET (C#, F#, and Visual Basic)
Supports Npgsql, Dapper, Entity Framework Core, and Npgsql.FSharp
Follow the instructions for your database library:
- C# - Npgsql, Dapper, Entity Framework Core
- F# - Npgsql.FSharp
- Visual Basic - Npgsql
Or check out some examples:
- Embeddings with OpenAI
- Binary embeddings with Cohere
- Hybrid search with Ollama (Reciprocal Rank Fusion)
- Sparse search with Text Embeddings Inference
- Recommendations with Disco
- Topic modeling with ML.NET
- Horizontal scaling with Citus
- Bulk loading with
COPY
Run
dotnet add package PgvectorCreate a connection
var dataSourceBuilder = new NpgsqlDataSourceBuilder(connString);
dataSourceBuilder.UseVector();
await using var dataSource = dataSourceBuilder.Build();
var conn = dataSource.OpenConnection();Enable the extension
await using (var cmd = new NpgsqlCommand("CREATE EXTENSION IF NOT EXISTS vector", conn))
{
await cmd.ExecuteNonQueryAsync();
}
conn.ReloadTypes();Create a table
await using (var cmd = new NpgsqlCommand("CREATE TABLE items (id serial PRIMARY KEY, embedding vector(3))", conn))
{
await cmd.ExecuteNonQueryAsync();
}Insert a vector
await using (var cmd = new NpgsqlCommand("INSERT INTO items (embedding) VALUES ($1)", conn))
{
var embedding = new Vector(new float[] { 1, 1, 1 });
cmd.Parameters.AddWithValue(embedding);
await cmd.ExecuteNonQueryAsync();
}Get the nearest neighbors
await using (var cmd = new NpgsqlCommand("SELECT * FROM items ORDER BY embedding <-> $1 LIMIT 5", conn))
{
var embedding = new Vector(new float[] { 1, 1, 1 });
cmd.Parameters.AddWithValue(embedding);
await using (var reader = await cmd.ExecuteReaderAsync())
{
while (await reader.ReadAsync())
{
Console.WriteLine(reader.GetValue(0));
}
}
}Add an approximate index
await using (var cmd = new NpgsqlCommand("CREATE INDEX ON items USING hnsw (embedding vector_l2_ops)", conn))
{
await cmd.ExecuteNonQueryAsync();
}Use vector_ip_ops for inner product and vector_cosine_ops for cosine distance
See a full example
Run
dotnet add package Pgvector.DapperImport the library
using Pgvector.Dapper;Create a connection
SqlMapper.AddTypeHandler(new VectorTypeHandler());
var dataSourceBuilder = new NpgsqlDataSourceBuilder(connString);
dataSourceBuilder.UseVector();
await using var dataSource = dataSourceBuilder.Build();
var conn = dataSource.OpenConnection();Enable the extension
conn.Execute("CREATE EXTENSION IF NOT EXISTS vector");
conn.ReloadTypes();Define a class
public class Item
{
public int Id { get; set; }
public Vector? Embedding { get; set; }
}Also supports HalfVector and SparseVector
Create a table
conn.Execute("CREATE TABLE items (id serial PRIMARY KEY, embedding vector(3))");Insert a vector
var embedding = new Vector(new float[] { 1, 1, 1 });
conn.Execute(@"INSERT INTO items (embedding) VALUES (@embedding)", new { embedding });Get the nearest neighbors
var embedding = new Vector(new float[] { 1, 1, 1 });
var items = conn.Query<Item>("SELECT * FROM items ORDER BY embedding <-> @embedding LIMIT 5", new { embedding });
foreach (Item item in items)
{
Console.WriteLine(item.Embedding);
}Add an approximate index
conn.Execute("CREATE INDEX ON items USING hnsw (embedding vector_l2_ops)");
// or
conn.Execute("CREATE 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
See a full example
Run
dotnet add package Pgvector.EntityFrameworkCoreThe latest version works with .NET 8 and 9. For .NET 6 and 7, use version 0.1.2 and this readme.
Import the library
using Pgvector.EntityFrameworkCore;Enable the extension
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.HasPostgresExtension("vector");
}Configure the connection
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseNpgsql("connString", o => o.UseVector());
}Define a model
public class Item
{
public int Id { get; set; }
[Column(TypeName = "vector(3)")]
public Vector? Embedding { get; set; }
}Also supports HalfVector and SparseVector
Insert a vector
ctx.Items.Add(new Item { Embedding = new Vector(new float[] { 1, 1, 1 }) });
ctx.SaveChanges();Get the nearest neighbors
var embedding = new Vector(new float[] { 1, 1, 1 });
var items = await ctx.Items
.OrderBy(x => x.Embedding!.L2Distance(embedding))
.Take(5)
.ToListAsync();
foreach (Item item in items)
{
if (item.Embedding != null)
{
Console.WriteLine(item.Embedding);
}
}Also supports MaxInnerProduct, CosineDistance, L1Distance, HammingDistance, and JaccardDistance
Get the distance
var items = await ctx.Items
.Select(x => new { Entity = x, Distance = x.Embedding!.L2Distance(embedding) })
.ToListAsync();Get items within a certain distance
var items = await ctx.Items
.Where(x => x.Embedding!.L2Distance(embedding) < 5)
.ToListAsync();Add an approximate index
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Item>()
.HasIndex(i => i.Embedding)
.HasMethod("hnsw")
.HasOperators("vector_l2_ops")
.HasStorageParameter("m", 16)
.HasStorageParameter("ef_construction", 64);
// or
modelBuilder.Entity<Item>()
.HasIndex(i => i.Embedding)
.HasMethod("ivfflat")
.HasOperators("vector_l2_ops")
.HasStorageParameter("lists", 100);
}Use vector_ip_ops for inner product and vector_cosine_ops for cosine distance
See a full example
Run
dotnet add package PgvectorImport the library
open PgvectorCreate a connection
let dataSourceBuilder = new NpgsqlDataSourceBuilder(connString)
dataSourceBuilder.UseVector()
use dataSource = dataSourceBuilder.Build()Enable the extension
dataSource
|> Sql.fromDataSource
|> Sql.query "CREATE EXTENSION IF NOT EXISTS vector"
|> Sql.executeNonQueryCreate a table
dataSource
|> Sql.fromDataSource
|> Sql.query "CREATE TABLE items (id serial PRIMARY KEY, embedding vector(3))"
|> Sql.executeNonQueryInsert a vector
let embedding = new Vector([| 1f; 1f; 1f |])
let parameter = new NpgsqlParameter("", embedding)
dataSource
|> Sql.fromDataSource
|> Sql.query "INSERT INTO items (embedding) VALUES (@embedding)"
|> Sql.parameters [ "embedding", Sql.parameter parameter ]
|> Sql.executeNonQueryGet the nearest neighbors
type Item = {
Id: int
Embedding: Vector
}
dataSource
|> Sql.fromDataSource
|> Sql.query "SELECT * FROM items ORDER BY embedding <-> @embedding LIMIT 5"
|> Sql.parameters [ "embedding", Sql.parameter parameter ]
|> Sql.execute (fun read ->
{
Id = read.int "id"
Embedding = read.fieldValue<Vector> "embedding"
})
|> printfn "%A"Add an approximate index
dataSource
|> Sql.fromDataSource
|> Sql.query "CREATE INDEX ON items USING hnsw (embedding vector_l2_ops)"
|> Sql.executeNonQueryUse vector_ip_ops for inner product and vector_cosine_ops for cosine distance
See a full example
Run
dotnet add package PgvectorCreate a connection
Dim dataSourceBuilder As New NpgsqlDataSourceBuilder(connString)
dataSourceBuilder.UseVector()
Dim dataSource = dataSourceBuilder.Build()
Dim conn = dataSource.OpenConnection()Enable the extension
Using cmd As New NpgsqlCommand("CREATE EXTENSION IF NOT EXISTS vector", conn)
cmd.ExecuteNonQuery()
End Using
conn.ReloadTypes()Create a table
Using cmd As New NpgsqlCommand("CREATE TABLE items (id serial PRIMARY KEY, embedding vector(3))", conn)
cmd.ExecuteNonQuery()
End UsingInsert a vector
Using cmd As New NpgsqlCommand("INSERT INTO items (embedding) VALUES ($1)", conn)
Dim embedding As New Vector(New Single() {1, 1, 1})
cmd.Parameters.AddWithValue(embedding)
cmd.ExecuteNonQuery()
End UsingGet the nearest neighbors
Using cmd As New NpgsqlCommand("SELECT * FROM items ORDER BY embedding <-> $1 LIMIT 5", conn)
Dim embedding As New Vector(New Single() {1, 1, 1})
cmd.Parameters.AddWithValue(embedding)
Using reader As NpgsqlDataReader = cmd.ExecuteReader()
While reader.Read()
Console.WriteLine(reader.GetValue(0))
End While
End Using
End UsingAdd an approximate index
Using cmd As New NpgsqlCommand("CREATE INDEX ON items USING hnsw (embedding vector_l2_ops)", conn)
cmd.ExecuteNonQuery()
End UsingUse vector_ip_ops for inner product and vector_cosine_ops for cosine distance
See a full example
Create a vector from an array
var vec = new Vector(new float[] { 1, 2, 3 });Get an array
var arr = vec.ToArray();Create a half vector from an array
var vec = new HalfVector(new Half[] { (Half)1, (Half)2, (Half)3 });Get an array
var arr = vec.ToArray();Create a sparse vector from an array
var vec = new SparseVector(new float[] { 1, 0, 2, 0, 3, 0 });Or a dictionary of non-zero elements
var dictionary = new Dictionary<int, float>();
dictionary.Add(0, 1);
dictionary.Add(2, 2);
dictionary.Add(4, 3);
var vec = new SparseVector(dictionary, 6);Note: Indices start at 0
Get the number of dimensions
var dim = vec.Dimensions;Get the indices of non-zero elements
var indices = vec.Indices;Get the values of non-zero elements
var values = vec.Values;Get an array
var arr = vec.ToArray();Everyone is encouraged to help improve this project. Here are a few ways you can help:
- Report bugs
- Fix bugs and submit pull requests
- Write, clarify, or fix documentation
- Suggest or add new features
To get started with development:
git clone https://github.com/pgvector/pgvector-dotnet.git
cd pgvector-dotnet
createdb pgvector_dotnet_test
dotnet testTo run an example:
cd examples/Loading
createdb pgvector_example
dotnet run