All checks were successful
CI/CD / detect-changes (push) Successful in 4s
CI/CD / test-runners (push) Has been skipped
CI/CD / test-frontend (push) Has been skipped
CI/CD / e2e-smoke (push) Has been skipped
CI/CD / test-sqlite (push) Successful in 2m59s
CI/CD / test-go-pg (push) Successful in 2m58s
CI/CD / build-and-deploy (push) Successful in 1m14s
Co-authored-by: Jeffrey Smith <jasafpro@gmail.com> Co-committed-by: Jeffrey Smith <jasafpro@gmail.com>
2.7 KiB
2.7 KiB
Design: Vector Column Type (v0.8.3)
Problem
Extensions building semantic search, RAG, or recommendation features need to store and query high-dimensional vectors (embeddings). Without kernel-level support, each extension would need to reinvent storage, serialization, and similarity search — duplicating effort and missing the pgvector optimization path.
Design
Three-tier progressive enhancement
| Backend | Column DDL | Storage | Search |
|---|---|---|---|
| Postgres + pgvector | vector(N) + HNSW index |
Native vector type | <=> operator (index-backed) |
| Postgres (no pgvector) | JSONB |
JSON array | Go-side cosine distance |
| SQLite | TEXT |
JSON string | Go-side cosine distance |
Extensions declare "vector(N)" in their manifest db_tables block.
The kernel maps this to the appropriate SQL type at install time based on
detected capabilities.
Manifest example
{
"db_tables": {
"documents": {
"columns": {
"title": "text",
"embedding": "vector(384)"
}
}
},
"capabilities": {
"optional": ["pgvector"]
}
}
API surface
# Insert (vector as list)
db.insert("documents", {"title": "hello", "embedding": [0.1, 0.2, ...]})
# Similarity search
rows = db.query_similar(
"documents", "embedding",
vector=[0.1, 0.2, ...],
limit=10,
filters={"active": True},
metric="cosine"
)
# → [{..., "_distance": 0.023}, ...]
Dispatch paths
pgvector path — SQL-side computation with index:
SELECT *, (embedding <=> $1::vector) AS _distance
FROM ext_pkg_documents
WHERE ... ORDER BY embedding <=> $1::vector LIMIT $2
Fallback path — Go-side computation:
SELECT * FROM table WHERE filters LIMIT 1000- Parse each row's vector column from JSON
- Compute cosine distance in Go
- Sort by distance, return top N with
_distanceinjected
Dimension validation
- Manifest: 1 ≤ N ≤ 4096 (validated by
parseVectorDim) - Insert-time: no dimension validation (store whatever list is given)
- Query-time: dimension mismatches produce distance = 1.0 (treated as unrelated)
Performance characteristics
| Path | 1K rows | 10K rows | 100K rows |
|---|---|---|---|
| pgvector (HNSW) | <1ms | <5ms | <10ms |
| Fallback (Go) | <10ms | ~100ms | Not recommended |
Fallback caps at 1000 rows fetched. Extensions needing large-scale similarity
search should declare capabilities.optional: ["pgvector"] and degrade
gracefully.
Limitations
- Only cosine distance metric (v0.8.3). L2 / inner product can be added later.
- No dimension validation at insert time.
- Fallback path fetches at most 1000 rows — not suitable for large datasets.
- HNSW index is only created for pgvector backends.