A tiny SQL-only PostgreSQL extension that adds a dynamic embedding composite type (polyvec) on top of pgvector.
It lets you store one of several supported vector dimensions in a single column, and provides search helpers that automatically route to the correct internal slot based on the query vector's dimension.
In this repo, dimensions 3/4/5/6 are used as stand-ins for 384/768/1024/1536 to keep examples short and runnable. Replace with real dimensions in production forks or future versions.
pgvector requires fixed dimensions per vector(N) column. If you use multiple embedding models (or change models over time), you can end up with multiple columns or multiple tables.
polyvec provides a single column that can hold one of several supported dimensions while still allowing dimension-specific routing for querying.
polyveccomposite type with:dimsandslotmetadata- multiple fixed-size vector subfields (
v384,v768,v1024,v1536)
- helpers:
polyvec_set_embedding(polyvec, vector) -> polyvecpolyvec_get_embedding(polyvec) -> vectorpolyvec_convert(vector) -> polyvecpolyvec_validate(polyvec) -> boolean
- search functions:
polyvec_search_l2(tbl regclass, poly_col text, q vector, k int=10)polyvec_search_cosine(...)polyvec_search_ip(...)
All search functions return:
data(JSONB of the full row with fully-qualified keys likepublic.docs.title)distance(float8)slot(which internal slot was used)
- Find Postgres sharedir on the server:
pg_config --sharedir
- Copy:
polyvector.control→<sharedir>/extension/sql/polyvector--1.0.sql→<sharedir>/extension/
- In SQL:
CREATE EXTENSION vector; CREATE EXTENSION polyvector;
If you have pg_config available:
make installThen in SQL:
CREATE EXTENSION vector;
CREATE EXTENSION polyvector;If Postgres runs in a container, the files must be copied into the container's extension directory.
Run the demo script:
psql -d <yourdb> -f examples/polyvec-sample.sqlOr call search directly:
SELECT *
FROM polyvec_search_l2(
'public.docs'::regclass,
'emb_b',
'[0.01, 0.02, 0.03, 0.05]'::vector(4),
5
);For real workloads, create slot-specific indexes matching the operator you use.
Example (HNSW, L2) for docs.emb_b when dims=4 maps to v768:
CREATE INDEX ON public.docs
USING hnsw (((emb_b).v768) vector_l2_ops);Cosine:
CREATE INDEX ON public.docs
USING hnsw (((emb_b).v768) vector_cosine_ops);Inner product:
CREATE INDEX ON public.docs
USING hnsw (((emb_b).v768) vector_ip_ops);Repeat per slot (v384, v768, v1024, v1536) and per polyvec column as needed.
- Only one slot is intended to be populated per row (enforced by
polyvec_validate). - Query results are dimension-specific: a
vector(4)query only searches rows whosepolyvec.dims = 4. - This is a SQL-only extension; no C code and no background workers.
MIT. See LICENSE.