Vector search with pgvector¶
PostGamma 0.1.0a1 bundles pgvector 0.8.6 into the embedded kernel. The wheel
and static C SDK contain its native code, control file, and installation SQL;
no PostgreSQL server package or separately loaded vector.so is required.
Check availability¶
Bundled means that the code is available to a cluster. It does not silently install SQL objects into every logical database. Inspect the build and then enable the extension once in each database that needs it:
import postgamma
database = postgamma.Database("vectors.pgm")
available = {item.sql_name: item for item in database.bundled_extensions()}
print(available["vector"].version) # 0.8.6
with database.connect(autocommit=True) as connection:
connection.execute("create extension if not exists vector")
CREATE EXTENSION is transactional PostgreSQL DDL. After it commits, the
extension remains installed when the embedded instance closes and reopens.
An unbundled native extension still fails closed instead of loading a host
shared object.
Run a nearest-neighbor query¶
The complete runnable example creates a persistent cluster, enables pgvector, builds an HNSW index, and performs a parameterized search:
import postgamma
with postgamma.connect("vectors.pgm", autocommit=True) as connection:
bundled = {
extension.sql_name: extension
for extension in connection.database.bundled_extensions()
}
vector = bundled["vector"]
print(f"Bundled pgvector {vector.version}")
connection.execute("create extension if not exists vector")
connection.execute(
"create table if not exists documents("
"id bigint primary key, label text not null, embedding vector(3) not null)"
)
connection.execute(
"insert into documents values "
"(1, 'alpha', '[1,1,1]'), "
"(2, 'beta', '[2,2,2]'), "
"(3, 'gamma', '[3,3,3]') "
"on conflict (id) do update set "
"label = excluded.label, embedding = excluded.embedding"
)
connection.execute(
"create index if not exists documents_embedding_hnsw "
"on documents using hnsw (embedding vector_l2_ops)"
)
nearest = connection.execute(
"select id, label from documents "
"order by embedding <-> $1::vector limit 1",
["[1,1,1]"],
).fetchone()
print(nearest)
Run it with:
It prints:
Python strings are suitable parameters when SQL gives PostgreSQL the target
type, as in $1::vector. Vector result OIDs are extension-defined, so cast a
vector to text for a string result or register a custom PostGamma codec when
the application needs a dedicated Python vector class.
Choose an index¶
HNSW supports strong query performance without a training step and can be created on an empty table:
IVFFlat should normally be built after representative data has been loaded:
CREATE INDEX documents_embedding_ivfflat
ON documents USING ivfflat (embedding vector_l2_ops)
WITH (lists = 100);
ANALYZE documents;
The distance operator in the query must match the operator class selected by the index. The common pairs are:
| Search | Operator | Operator class |
|---|---|---|
| Euclidean distance | <-> |
vector_l2_ops |
| Negative inner product | <#> |
vector_ip_ops |
| Cosine distance | <=> |
vector_cosine_ops |
| L1 distance | <+> |
vector_l1_ops |
Refer to the pgvector 0.8.6 SQL behavior for additional halfvec, bit, and
sparsevec types and their compatible operator classes.
Sessions, workers, and settings¶
hnsw.ef_search, hnsw.iterative_scan, ivfflat.probes, and
ivfflat.iterative_scan are PostgreSQL settings. A SET applies to that
logical connection; it does not leak to another connection or another live
embedded instance. SET LOCAL remains scoped to the current transaction.
PostGamma's release gate builds HNSW and IVFFlat indexes, resolves pgvector's parallel-build worker entries through the static extension registry, executes vector functions in PostgreSQL parallel workers, runs searches concurrently in two live clusters, and verifies the indexes after close and reopen.
Static C SDK¶
The C API does not add a separate vector-specific surface. Open an instance and
connection with the normal pgm_* API, execute CREATE EXTENSION vector, and
send the same SQL shown above. This keeps pgvector behavior, types, errors, and
query planning identical across the Python and C forms of the product.
The static SDK archive includes licenses/LICENSE.pgvector; applications that
redistribute the linked extension must preserve the supplied notices.