Documentation
¶
Overview ¶
Package pgvector provides a PostgreSQL + pgvector implementation of the VectorStore interface.
Index ¶
- Constants
- func Available(ctx context.Context, db *grove.DB) (ok bool, reason string, err error)
- func Migrate(ctx context.Context, db *grove.DB, dimensions int) error
- func Migrations(dimensions int) (*migrate.Group, error)
- type Option
- type Store
- func (s *Store) CheckDimensions(ctx context.Context) error
- func (s *Store) Delete(ctx context.Context, ids []string) error
- func (s *Store) DeleteByMetadata(ctx context.Context, filter map[string]string) error
- func (s *Store) Describe() weave.ComponentInfo
- func (s *Store) Search(ctx context.Context, vector []float32, opts *vectorstore.SearchOptions) ([]vectorstore.SearchResult, error)
- func (s *Store) Upsert(ctx context.Context, entries []vectorstore.Entry) error
- type VectorEntry
Constants ¶
const GroupName = "weave_pgvector"
GroupName is the grove migration group that owns the vector table. It is separate from the metadata store's "weave" group, so a host that never turns pgvector on never needs the vector extension.
const MaxIndexedDimensions = 2000
MaxIndexedDimensions is the largest vector an HNSW index accepts.
Variables ¶
This section is empty.
Functions ¶
func Available ¶
Available reports whether weave can use pgvector on db: true when the vector extension (0.5.0 or later) is installed or can be created by this role. When false, reason says why in one sentence. err is for failures to ask (a connection error), never for "no". It changes nothing.
To learn whether the role may create the extension, Available runs CREATE EXTENSION IF NOT EXISTS vector inside a transaction it always rolls back, so a host can call it at boot to decide whether to turn knowledge on without making pgvector a requirement. Replicas booting together may run it while another replica's Migrate is creating the extension: the probe then loses on pg_extension's unique index, and Available reads the committed extension instead of reporting a refusal. A lock or statement timeout, a cancellation or a deadlock is an error, not a reason.
func Migrate ¶
Migrate runs Migrations(dimensions) through grove's orchestrator, then checks the live table's dimensions (ErrDimensionMismatch). Replicas booting together on a database without grove's tracking tables race on creating them, so a lost race is retried a few times, as the postgres metadata store's Migrate does.
func Migrations ¶
Migrations returns the tracked group that creates the vector extension, the weave_vectors table with an embedding vector(dimensions) column, and its indexes. dimensions outside 1..MaxIndexedDimensions is ErrInvalidArgument. The group depends on no other group, so a host runs it on its own or adds it to its own orchestrator run.
The migration is recorded once, so it never runs again with another dimensions. When weave_vectors already exists, made by hand or by an earlier run, the migration fails with ErrDimensionMismatch if its embedding column has another size, and nothing is recorded. Call Store.CheckDimensions after a run that applied nothing to catch a changed setting.
Types ¶
type Option ¶
type Option func(*Store)
Option configures the pgvector Store.
func WithDimensions ¶
WithDimensions sets the embedding size the store expects, the one its table was created with. CheckDimensions compares the two.
func WithTableName ¶
WithTableName sets a custom table name (default: "weave_vectors"). Every statement the store runs names it. Migrations only ever creates weave_vectors, so a custom table is yours to create, with the same columns.
type Store ¶
type Store struct {
// contains filtered or unexported fields
}
Store is a PostgreSQL + pgvector vector store.
func (*Store) CheckDimensions ¶
CheckDimensions compares the table's embedding column with WithDimensions: ErrDimensionMismatch naming both numbers, or ErrNoVectorStore when the table does not exist. Without WithDimensions it is ErrInvalidArgument.
func (*Store) DeleteByMetadata ¶
DeleteByMetadata removes entries matching the given metadata filter. An empty filter would match every row and is ErrInvalidArgument.
func (*Store) Describe ¶
func (s *Store) Describe() weave.ComponentInfo
Describe reports the pgvector store. It scores 1 - cosine distance, and every search filters metadata->>'tenant_id' = TenantKey, which Search refuses to run empty.
func (*Store) Search ¶
func (s *Store) Search(ctx context.Context, vector []float32, opts *vectorstore.SearchOptions) ([]vectorstore.SearchResult, error)
Search returns the most similar entries of one tenant to the given vector. An empty TenantKey is ErrTenantRequired.
HNSW applies the tenant and metadata filters after it walks the graph, so on its own a tenant with few vectors in a large table can get fewer than TopK hits, or none. On pgvector 0.8.0 and later Search runs in a transaction that first sets hnsw.iterative_scan = strict_order, so the index keeps scanning until it has TopK matching rows in exact distance order (up to hnsw.max_scan_tuples). Older versions search without it.
type VectorEntry ¶
type VectorEntry struct {
grove.BaseModel `grove:"table:weave_vectors"`
ID string `grove:"id,pk"`
Vector []float32 `grove:"embedding,type:vector"`
Content string `grove:"content"`
Metadata map[string]string `grove:"metadata,type:jsonb"`
}
VectorEntry is the grove model for a row of the default weave_vectors table. The store itself writes raw SQL against whichever table WithTableName names; the model is kept for callers that read the table through grove.