Franck PachotDatabase Developer Advocate Minibook 36 · Database field guides All minibooks

Database field guide · 36

Filtered Vector Search

Eligibility, ANN traversal, recall, and adaptive plans

Make vector search filters correct and measurable by distinguishing pre-filtering, traversal filtering, post-filtering, and exact fallbacks.

Franck Pachot7 chaptersvector filters · ANN · recall · pgvector

Build the mental model before choosing the mechanism.

This minibook was AI-generated from Franck Pachot's archived blog posts. Links to the original articles are included for source context and verification.

01

Filtering changes the search problem

Nearest neighbors among all rows are not necessarily nearest neighbors among eligible rows. Tenant, category, time, and authorization predicates redefine the population whose top-k must be found.

  • Define exact filtered top-k as the quality baseline.
  • Measure selectivity by query cohort.
  • Never treat an authorization filter as optional ranking.

02

Post-filtering can starve results

An ANN index may retrieve global neighbors and discard ineligible rows afterward. A selective filter can then return fewer than k rows or poor filtered recall even when unfiltered ANN recall is high.

  • Record requested k and returned count.
  • Sweep traversal effort at several selectivities.
  • Do not infer recall from plausible distances.

03

Pre-filtering narrows before ranking

A system that applies an exact predicate before vector traversal searches only eligible rows, preserving semantics but potentially changing index and memory costs. Product terminology must be verified from the plan.

  • Distinguish logical eligibility from physical execution.
  • Inspect rows entering distance evaluation.
  • Include filter-index maintenance cost.

04

Integrated indexes can filter during traversal

Some vector indexes attach filterable attributes or combine graph and relational navigation. This may retain more useful candidates than post-filtering without building one index per tenant.

  • Test skewed and sparse values.
  • Measure index build and update amplification.
  • Verify which operators are pushed into traversal.

05

Adaptive effort handles selectivity

Fixed ANN parameters cannot serve both broad and highly selective filters efficiently. Iterative scans, larger candidate budgets, exact scans, or partitioned strategies can adapt to eligible cardinality.

  • Set a latency and work ceiling.
  • Choose exact fallback from measured crossover points.
  • Avoid unbounded retries to fill k.

06

Evaluate filtered recall directly

For sampled query vectors and predicates, compute exact filtered neighbors and compare the approximate result. Report recall, result completeness, latency, and work by selectivity bucket.

  • Keep the same distance metric and tie policy.
  • Include empty and tiny eligible sets.
  • Version data, indexes, and ANN settings.

07

Field manual

Concrete mechanics, diagnostic evidence, and executable patterns to carry into a real system.

01

Create an exact filtered baseline

Compute exact neighbors after applying the predicate for a sampled evaluation set. This defines correctness independently of an ANN implementation.

SELECT id, embedding <=> $1 AS distance
FROM item WHERE tenant_id = $2 AND category = $3
ORDER BY embedding <=> $1, id LIMIT 20;
02

Detect post-filter starvation

Record returned count and recall while sweeping filter selectivity and ANN effort. Fewer than k rows is an immediate completeness signal.

SET LOCAL hnsw.ef_search = 100;
EXPLAIN (ANALYZE, BUFFERS)
SELECT id FROM item WHERE category = $1
ORDER BY embedding <=> $2 LIMIT 20;
03

Choose an exact fallback

For a small eligible set, an indexed relational filter plus exact distance calculation can beat repeated ANN traversal and guarantees filtered top-k.

WITH eligible AS MATERIALIZED (
  SELECT id, embedding FROM item WHERE tenant_id=$1 AND category=$2
)
SELECT id FROM eligible ORDER BY embedding <=> $3 LIMIT 20;
04

Report quality by selectivity

Average recall hides failures on rare filter values. Bucket evaluations by eligible cardinality and include result completeness.

buckets = ['0-10', '11-100', '101-10k', '>10k']
report per bucket: queries, returned/k, recall@k, p50_ms, p95_ms

08

Source articles

Optional deep dives with the complete experiments and product-version context behind this guide.