Lesson 6 / 28
Distance Operators and ORDER BY
Use <->, <=> and <#> to rank rows by similarity.
Three operators, one pattern
pgvector exposes distances as operators: <-> Euclidean (L2) distance, <=> cosine distance (1 minus cosine similarity), and <#> the negative inner product (negative so that "smaller is closer" holds for every operator and ascending ORDER BY always means "nearest first"). The search pattern is always ORDER BY embedding <op> :query LIMIT k. To show a cosine similarity, compute 1 - (embedding <=> query); to show an inner product, multiply <#> by -1. Use the operator that matches your index (an HNSW index built with vector_cosine_ops is used for <=> queries, not for <->) and the metric your embedding model was trained for.
The three distances for one query, run
I ran this SQL on PostgreSQL 16 with the pgvector extension, version 0.8.6, in a Docker container. For the query [1,0,0] the nearest row by cosine is the 2025 leave policy (cosine distance 0.006). The columns show L2 distance, cosine distance and the inner product (negated back to a positive similarity).
SELECT id, body,
round((embedding <-> '[1,0,0]')::numeric, 3) AS l2,
round((embedding <=> '[1,0,0]')::numeric, 3) AS cosine_distance,
round(((embedding <#> '[1,0,0]') * -1)::numeric, 3) AS inner_product
FROM docs ORDER BY embedding <=> '[1,0,0]' LIMIT 3;
Output:
id | body | l2 | cosine_distance | inner_product ----+------------------------+-------+-----------------+--------------- 1 | leave policy 2025 | 0.141 | 0.006 | 0.900 4 | beta confidential memo | 0.224 | 0.024 | 0.900 2 | old leave policy | 0.300 | 0.037 | 0.800 (3 rows)
Use the metric your model was trained for
Most text embedding models are meant for cosine similarity. Read the model card and create the index with the matching operator class.
Quick check: Why is <#> the negative inner product?
- Inner products are negative by nature
- It is a bug
- To save space
- So ascending ORDER BY always returns nearest first for every operator
Answer
So ascending ORDER BY always returns nearest first for every operator — A larger inner product means closer, so it is negated to fit "smaller is closer".