Getting Started: pgvector
PGVector is an open-source vector similarity search for Postgres
PGVector supports:
- exact and approximate nearest neighbor search
- L2 distance, inner product, and cosine distance
- IVFFlat and HNSW index types
See the installation instructions.
Usage with LangChainGo
In code, create an embedder based on an LLM (OpenAI, Ollama, etc.):
llm, _:= openai.New()
emb, _ := embeddings.NewEmbedder(llm)
For OpenAI embeddings, you will need obtain an API key and provide as an environment variable to the program:
export OPENAI_API_KEY=your_openai_api_key_here
Create a vector store:
ctx := context.Background()
store, err := pgvector.New(
ctx,
pgvector.WithConnectionURL("postgres://testuser:testpass@localhost:5432/testdb?sslmode=disable"),
pgvector.WithEmbedder(emb),
)
Document tables will be created automatically.
Add documents:
_, err = store.AddDocuments(context.Background(), []schema.Document{
{
PageContent: "Tokyo",
Metadata: map[string]any{
"population": 38,
"area": 2190,
},
},
{
PageContent: "Sao Paulo",
Metadata: map[string]any{
"population": 22.6,
"area": 1523,
},
},
})
Run a similarity search using cosine distance (<=>):
filter := map[string]any{"area": "1523"}
docs, err = store.SimilaritySearch(ctx, "only cities in south america",
10,
vectorstores.WithScoreThreshold(0.80),
vectorstores.WithFilters(filter),
)
For now, pgvector integration only supports simple key-value filters and cosine distance search.
Full example
Here is the entire program (from pgvector-vectorstore-example):
package main
import (
"context"
"fmt"
"log"
"github.com/vxcontrol/langchaingo/embeddings"
"github.com/vxcontrol/langchaingo/llms/openai"
"github.com/vxcontrol/langchaingo/schema"
"github.com/vxcontrol/langchaingo/vectorstores"
"github.com/vxcontrol/langchaingo/vectorstores/pgvector"
)
func main() {
// Create an embeddings client using the OpenAI API. Requires environment variable OPENAI_API_KEY to be set.
llm, err := openai.New()
if err != nil {
log.Fatal(err)
}
e, err := embeddings.NewEmbedder(llm)
if err != nil {
log.Fatal(err)
}
// Create a new pgvector store.
ctx := context.Background()
store, err := pgvector.New(
ctx,
pgvector.WithConnectionURL("postgres://testuser:testpass@localhost:5432/testdb?sslmode=disable"),
pgvector.WithEmbedder(e),
)
if err != nil {
log.Fatal(err)
}
// Add documents to the pgvector store.
_, err = store.AddDocuments(context.Background(), []schema.Document{
{
PageContent: "Tokyo",
Metadata: map[string]any{
"population": 38,
"area": 2190,
},
},
{
PageContent: "Paris",
Metadata: map[string]any{
"population": 11,
"area": 105,
},
},
{
PageContent: "London",
Metadata: map[string]any{
"population": 9.5,
"area": 1572,
},
},
{
PageContent: "Santiago",
Metadata: map[string]any{
"population": 6.9,
"area": 641,
},
},
{
PageContent: "Buenos Aires",
Metadata: map[string]any{
"population": 15.5,
"area": 203,
},
},
{
PageContent: "Rio de Janeiro",
Metadata: map[string]any{
"population": 13.7,
"area": 1200,
},
},
{
PageContent: "Sao Paulo",
Metadata: map[string]any{
"population": 22.6,
"area": 1523,
},
},
})
if err != nil {
log.Fatal(err)
}
// Search for similar documents.
docs, err := store.SimilaritySearch(ctx, "japan", 1)
if err != nil {
log.Fatal(err)
}
fmt.Println(docs)
// Search for similar documents using score threshold.
docs, err = store.SimilaritySearch(ctx, "only cities in south america", 10, vectorstores.WithScoreThreshold(0.80))
if err != nil {
log.Fatal(err)
}
fmt.Println(docs)
// Search for similar documents using score threshold and metadata filter.
// Metadata filter for pgvector only supports key-value pairs for now.
filter := map[string]any{"area": "1523"} // Sao Paulo
docs, err = store.SimilaritySearch(ctx, "only cities in south america",
10,
vectorstores.WithScoreThreshold(0.80),
vectorstores.WithFilters(filter),
)
if err != nil {
log.Fatal(err)
}
fmt.Println(docs)
}