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.
Timeseries
The telemetry port over TimescaleDB — bulk ingest that bypasses the event path, range reads, and structural tenancy on a hypertable with no RLS.
Documents
The CRDT document plane — append-only update log, seq-vector sync, compaction, and quiet-window materialization back into ordinary entities.