Fabriq

Vector

The embedding port over pgvector — upsert caller-supplied embeddings and cosine nearest-neighbour search through an HNSW index.

The vector plane stores and searches embeddings for similarity queries — semantic search, recommendation, deduplication. It is implemented in adapters/postgres on pgvector, backed by an HNSW index over the fabriq_embeddings table. Fabriq stores and searches vectors; it does not produce them — the caller supplies embeddings as []float32 from whatever model they run.

type VectorQuerier interface {
	Upsert(ctx context.Context, entity, id string, embedding []float32, meta map[string]any) error
	Similar(ctx context.Context, q VectorQuery, into any) error
}

Reach it through f.Vector(). Every operation is tenant-scoped structurally, like the rest of the Postgres adapter (SET LOCAL app.tenant_id plus an explicit tenant_id predicate) — see Tenancy.

Upsert

Upsert writes (or overwrites) one embedding keyed by (entity, id), with optional metadata stored alongside it. An empty embedding is rejected.

embedding := embedModel.Encode("centrifugal pump, 50 HP, stainless") // []float32 from your model

err := f.Vector().Upsert(ctx, "asset", assetID, embedding, map[string]any{
	"site_id": siteID,
	"kind":    "pump",
})

The upsert is keyed on (tenant_id, entity, id): re-upserting the same id replaces the embedding and metadata.

Similar

Similar runs a cosine nearest-neighbour search through the HNSW index. It scans into *[]query.VectorMatch, best match first.

type VectorQuery struct {
	Entity    string
	Embedding []float32
	K         int
}

type VectorMatch struct {
	ID    string
	Score float64 // cosine similarity, higher is closer
	Meta  map[string]any
}
queryEmbedding := embedModel.Encode("high-pressure water pump")

var matches []query.VectorMatch
err := f.Vector().Similar(ctx, query.VectorQuery{
	Entity:    "asset",
	Embedding: queryEmbedding,
	K:         10,
}, &matches)
if err != nil {
	return err
}
for _, m := range matches {
	// m.ID is the aggregate id; m.Score is cosine similarity (higher = closer);
	// m.Meta is the metadata stored at Upsert.
}

Score is cosine similarity in [0, 1]-ish terms — higher is closer (the adapter returns 1 - cosine_distance). K defaults to 10 when unset. Results are scoped to the (tenant, entity) pair.

m.ID is the aggregate id you passed to Upsert. To get the full row, hydrate from Postgres with Relational().GetMany("asset", ids, &assets) — one batched query for the whole match set.

On this page