Skip to content

Vector Search (kNN)

VectorkNNHNSWIVFFLAT
Stable On by default · production-ready

Vector search finds the rows whose embedding is closest to a query vector. Brute-force distance is fine for a few thousand rows, but at scale you build a vector index so the search is sub-linear. AetheriusDB supports two index types over a TENSOR(N) column:

  • HNSW — graph-based, best recall at small-to-medium k.
  • IVFFLAT — centroid-based, lower memory and faster build at very large N.

Both work with the same SQL — you only change the index you point a query at.

At a few thousand rows a brute-force scan is fine; past that you want a vector index so search cost stops growing with the table. AetheriusDB gives you two proven index types over the same TENSOR(N) column and the same SQL, so you tune recall-vs-memory by swapping the index — not by rewriting your queries or moving to another system.

  • Sub-linear at scale — an index turns “scan every row” into “visit a few,” so latency stays flat as the table grows.
  • Pick your trade-off — HNSW for best recall, IVFFLAT for lower memory and faster builds; same query either way.
  • Filter first, then rank — an ordinary SQL predicate shrinks the candidate set before the distance math runs.

A kNN query over a built index is sub-linear — dramatically faster than brute-force distance once you’re past a few thousand rows — and the SQL pre-filter means the index only ranks the rows that already passed your WHERE clause.

The index sits on a single TENSOR(N) column. Tune it with an optional WITH (…) clause — the option names are pgvector-compatible.

-- HNSW: best recall at small-to-medium k
CREATE INDEX products_vec_hnsw
ON products (vec)
USING HNSW
WITH (m = 16, ef_construction = 64, ef_search = 40);
-- Or IVFFLAT: lower memory, faster build at very large N
CREATE INDEX products_vec_ivf
ON products (vec)
USING IVFFLAT
WITH (lists = 100, probes = 8);
IndexTuning options
HNSWm (graph degree), ef_construction (build-time candidate width), ef_search (query-time candidate width)
IVFFLATlists (number of centroids), probes (centroids scanned per query)

Unknown option keys or non-positive values are rejected at CREATE INDEX time, before the catalog is touched — a typo fails fast rather than at first query.

Order by the distance to a query vector and take the top k. When the query is a single-table ORDER BY TENSOR_L2(col, :q) LIMIT k (or TENSOR_COSINE) over an indexed column, the planner serves it straight from the index:

-- Served from the HNSW/IVFFLAT index: k-nearest by cosine distance.
SELECT id, name, price
FROM products
ORDER BY TENSOR_COSINE(vec, :q)
LIMIT 10;
-- Euclidean (L2) distance instead:
SELECT id, name
FROM products
ORDER BY TENSOR_L2(vec, :q) ASC
LIMIT 20;

Above the index’s ANN threshold the result is approximate (the standard approximate-nearest-neighbour contract); below it, it is exact. The fast-path applies to a single-table query with exactly one ORDER BY distance key and a LIMIT — anything richer (WHERE, GROUP BY, joins, OFFSET, DISTINCT) runs the normal plan.

For small tables you can skip the index entirely and rank directly with TENSOR_COSINE(vec, :q) — see Tensor & Vector Types.

The whole point of having vectors in the database is hybrid queries: narrow the candidate set with ordinary SQL predicates first, then rank what’s left by distance.

SELECT id, subject,
TENSOR_COSINE(embedding, :query_vec) AS dist
FROM support_tickets
WHERE created_at >= '2026-05-01'
AND region = 'EU'
ORDER BY dist ASC
LIMIT 10;
HNSWIVFFLAT
StrengthHighest recallLower memory, faster build
Best forSmall-to-medium k, recall-sensitive searchVery large datasets, throughput-focused
Tuningm / ef_construction / ef_search — good defaults out of the boxlists / probes — raise probes to trade speed for recall

Vector indexes stay current with your data automatically:

  • INSERT keeps the index current incrementally — no full rebuild per row.
  • DELETE / UPDATE are reflected exactly — results never include removed rows or stale versions, with no manual rebuild.
  • Bulk COPY is picked up automatically — the index is current as soon as the load completes.
  • Rows with a NULL / missing embedding are skipped, not errored.

Indexes are restart-safe: the definition and tuning are persisted in the catalog and the index rehydrates at boot.