Vector Search Queries

Nearest Neighbor

SELECT id, vector_distance(embedding, ARRAY[0.1, 0.3, -0.2, ...]) AS dist
FROM articles
ORDER BY dist LIMIT 10;

Returns the 10 nearest neighbors by the metric configured on the index (l2, cosine, inner_product, manhattan, chebyshev, hamming, jaccard, or pearson). The planner detects ORDER BY vector_distance(...) LIMIT k and rewrites it into an ANN top-k plan; no special SEARCH keyword is required.

SELECT title, vector_distance(embedding, ARRAY[0.1, 0.3, ...]) AS score
FROM articles
WHERE category = 'machine-learning'
ORDER BY score LIMIT 10;

The engine builds a Roaring Bitmap of matching IDs and selects the optimal strategy: pre-filter (selective filters), post-filter (broad filters), or brute-force (very selective).

Distance Function

SELECT id, vector_distance(embedding, $query_vec) AS dist
FROM articles
ORDER BY dist LIMIT 10;

Operator Forms

OperatorFunctionMetric
<->vector_distanceL2
<=>vector_cosine_distanceCosine
<#>vector_neg_inner_productNegative inner product
SELECT id FROM articles ORDER BY embedding <=> $query_vec LIMIT 10;

ANN Tuning (Named Arguments)

vector_distance and its cosine / inner-product peers accept named tuning arguments via =>. JSON-string options are not accepted — every option is a typed, closed-set named argument:

SELECT id, vector_distance(
    embedding, $query_vec,
    quantization => 'rabitq',
    oversample   => 4,
    ef_search    => 128,
    target_recall => 0.95
) AS dist
FROM articles
ORDER BY dist LIMIT 10;
ArgumentTypeNotes
quantizationstringnone, sq8, pq, binary, ternary, rabitq, bbq, opq
oversampleu8Candidates fetched before re-ranking. Default 3. Final rerank set is oversample × ef_search.
query_dimu32Coarse-to-fine on first-N dims of Matryoshka embeddings. None = full dimensionality.
meta_token_budgetu8MetaEmbed multivec scoring budget for MaxSim / PLAID
ef_searchu32HNSW / Vamana search-time beam width. Default 64.
target_recallf32Adaptive recall target. The cost-model planner picks oversample / ef_search to hit this.

Unknown names, duplicate keys, positional 3rd args, or wrong operators (= instead of =>) all return typed errors that list the canonical names.

Quantization Choice

CodecBits/dimRecall (typ.)When to pick it
none32100%Small index (< 1M vectors), latency not critical
sq88~99%Balanced default for medium index sizes
pq~2~95%Large memory-bound indexes; classic Product Quantization
opq~2~96%PQ + learned random rotation; minor accuracy bump over pq
rabitq1~97%Frontier 1-bit with O(1/√D) error bound (SIGMOD 2024)
bbq1~98%Centroid-asymmetric 1-bit + 14-byte corrective; oversample-rerank
binary1~85%Hamming-only, no rerank — for ultra-cold tiers
ternary1.58~96%BitNet-style {-1, 0, +1} — cold/hot pack for AVX-512

The cost-model planner (target_recall) will pick oversample and ef_search automatically once you set the recall target. Manually set those two only when you need a hard latency ceiling.

Index Implementations

You don't pick the underlying index directly — it's chosen by the planner from collection metadata + workload signals:

  • HNSW — in-memory hierarchical graph, the default for moderate-size indexes
  • Vamana / DiskANN — flat-beam SSD-resident graph for billion-scale on a single node (Tier 2 of the vector frontier)
  • NaviX adaptive-local filtered traversal (VLDB 2025) — switches per-hop between standard / directed / blind heuristics based on local selectivity. Replaces classic ACORN-1 filtered ANN.
  • SIEVE workload-driven subindex collections — the planner builds specialized HNSW subindices for stable predicates (e.g. tenant_id) and routes filtered queries to them.
  • MetaEmbed multi-vector + ColBERT MaxSim + PLAID (ICLR 2026) — learnable Meta Tokens replace per-token explosion; budgeted MaxSim at query time via meta_token_budget.
  • Matryoshka adaptive-dim querying — coarse-to-fine ranking on the first-N dimensions of MRL embeddings via query_dim.
  • SPFresh streaming updates (SOSP 2023) — LIRE topology-aware local rebalancing; no full-rebuild stalls when vectors are added/removed.

Vector-Primary Collections

By default, vectors are an index attached to a column on a normal collection — the document/strict store is the source of truth, and the vector index is a side path. For pure-vector workloads (RAG corpora, recommendation memory, embedding stores) you can flip a collection into vector-primary mode, where the vector index becomes the primary access path and the document store is a metadata sidecar:

CREATE COLLECTION corpus (
    id UUID DEFAULT gen_uuid_v7(),
    embedding FLOAT[384],
    title TEXT,
    tenant_id UUID,
    created_at TIMESTAMP DEFAULT now()
) WITH (
    primary='vector',
    vector_field='embedding',
    dim=384,
    metric='cosine',
    quantization='rabitq',
    m=32,
    ef_construction=200,
    payload_indexes=['tenant_id', 'created_at']
);
OptionNotes
primary'document' (default), 'strict', 'kv', or 'vector'
vector_fieldRequired when primary='vector'. Column name of the embedding.
dimRequired. Embedding dimensionality.
metric'cosine', 'l2', 'inner_product', etc.
quantizationStorage-level codec (same vocabulary as the query-time arg above).
m, ef_constructionHNSW build-time parameters.
payload_indexesPer-field equality / range / boolean indexes over the metadata sidecar for filtered ANN. Replaces Pinecone metadata filters.

In vector-primary mode the planner treats the vector index as the source of truth for IDs; metadata fetches only happen for hit IDs. Cross-engine queries, CRDT sync, and SQL semantics all keep working — primary='vector' is purely an access-path hint, not a different engine.

Default primary='document' is unchanged: the existing CREATE VECTOR INDEX ON ... syntax continues to work for vector-as-side-index workloads.

Hybrid Vector + Text (RRF)

SELECT title, rrf_score(
    vector_distance(embedding, $query_vec),
    bm25_score(body, 'transformer attention')
) AS score
FROM articles
LIMIT 10;

Reciprocal Rank Fusion merges BM25 text results with vector similarity in a single pass.

Multiple vector columns per collection

A collection can carry several vector indexes, one per embedding column — name the column in parentheses after the collection. Each index gets its own metric and parameters; queries pick the column they search:

CREATE VECTOR INDEX idx_text  ON products (text_embedding)  METRIC cosine DIM 384;
CREATE VECTOR INDEX idx_image  ON products (image_embedding) METRIC cosine DIM 512;

-- Search the text-embedding index:
SELECT id FROM products ORDER BY text_embedding  <=> $text_vec  LIMIT 10;
-- ...or the image-embedding index:
SELECT id FROM products ORDER BY image_embedding <-> $image_vec LIMIT 10;

Omitting (<column>) targets the collection's default (unnamed) vector field — fine when there's only one embedding column (as in the CREATE VECTOR INDEX idx_embed ON articles ... examples above).