Querying & Filtering
Distance Operators
pgvector supports six distance operators for ordering (ORDER BY) and threshold filtering:
| Operator | Metric | Supported Types | Notes |
|---|---|---|---|
<-> |
L2 (Euclidean) distance | vector, halfvec, sparsevec |
|
<#> |
Negative inner product | vector, halfvec, sparsevec |
Returns because PostgreSQL index scans only support ASC order |
<=> |
Cosine distance | vector, halfvec, sparsevec |
(range [0, 2]) |
<+> |
L1 (Taxicab / Manhattan) distance | vector, halfvec, sparsevec |
(\sum |
<~> |
Hamming distance | bit |
Number of differing bits (XOR popcount) |
<%> |
Jaccard distance | bit |
(1 - \frac{ |
If your vectors are already normalized to unit length (such as OpenAI text-embedding-3-* or BGE embeddings), prefer inner product (<#>) over cosine distance (<=>) for the best CPU throughput.
Nearest-Neighbor Queries
Calculating Distances & Similarity Scores
Retrieve the distance alongside each row:
Distance Threshold Queries
Get all rows within a given distance threshold:
Combine with ORDER BY and LIMIT to use an HNSW or IVFFlat index:
vchordIf you frequently query by distance radius, vchord provides a dedicated <<->> sphere operator (WHERE embedding <<->> sphere('[3,1,2]'::vector, 5)) that evaluates range predicates directly inside the vchordrq or vchordg index without requiring ORDER BY ... LIMIT. See Similarity Filter in vchord.
Aggregates
Compute the mean (AVG) or component-wise sum (SUM) of vectors:
Filtering (WHERE Clauses) & Iterative Index Scans
Combine vector search with relational predicates:
Indexing Filter Columns
- Standard B-tree index on the filter column (good when
category_id = 123matches a very small fraction of rows): - Partial vector index (ideal when you only filter by a few known values):
- Partitioning (ideal when filtering across a bounded set of high-volume tenants or time ranges):
Iterative Index Scans (pgvector 0.8.0+)
By default, approximate vector index scans examine a fixed number of candidates (hnsw.ef_search or ivfflat.probes). If a WHERE filter rejects most of those candidates, the query may return fewer rows than LIMIT.
Starting in pgvector 0.8.0, enable iterative index scans so the index automatically continues scanning until enough matching rows are found (or max_scan_tuples / max_probes is reached):
When using relaxed_order, results may be slightly out of order by distance; wrap the query in a CTE or subquery to re-sort the final LIMIT rows:
Controlling Iterative Scan Budgets
Hybrid Search
You can combine pgvector semantic similarity search with lexical full-text search using Reciprocal Rank Fusion (RRF).
Hybrid Search with PostgreSQL tsvector
Hybrid Search with vchord_bm25 or pg_bestmatch
For true Okapi BM25 ranking with document-length normalization and corpus IDF:
- Pair
pgvector(orvchord) withvchord_bm25andpg_tokenizer— see the Hybrid Search Guide. - Or generate BM25-weighted
sparsevecvectors directly inside PostgreSQL usingpg_bestmatchand index them withpgvectorHNSW (sparsevec_ip_ops).