Back to Devoured - August 13, 2026
DEVOURED
Filtered Vector Search: What ACORN Fixes, and What Fixes ACORN

Filtered Vector Search: What ACORN Fixes, and What Fixes ACORN

Data Qdrant
Metadata filters in vector search can disconnect HNSW graphs, but Qdrant mitigates this by balancing index-time repairs against search-time logic.
What: Dylan Couzon and Meina Ghafouri benchmarked Qdrant v1.18.2, finding that filtered queries can trap HNSW traversals on isolated islands of data unless index-time 'extra edges' or query-time 'ACORN' expansion are employed.
Why it matters: As vector databases mature, the industry is moving from simple ANN search to hybrid search (vector + relational filtering), necessitating sophisticated graph-repair techniques to maintain recall.
Takeaway: Test your vector index recall across different filter selectivity levels; if recall drops significantly on broad filters (e.g., 20% match), enable index-time extra edges or ACORN on specific query paths.
Deep dive
  • Metadata filters effectively remove nodes from the search graph, leading to 'disconnected islands' where traversals fail to find the true nearest neighbors.
  • Qdrant's 'filterable HNSW' adds extra edges at index time for indexed payload fields, maintaining graph connectivity at the cost of higher memory usage and build times.
  • ACORN (as defined by Patel et al.) repairs graphs at search time by expanding neighbor lookups, which is effective when index-time edges are missing or filters involve complex AND logic.
  • A query planner is critical: it chooses between full scans, graph traversal with ACORN, or direct payload index retrieval based on estimated filter cardinality.
  • Benchmark results show that broad filters need index-time repairs, while highly selective filters are better handled by bypassing the graph and using pure payload indexes.
Decoder
  • HNSW (Hierarchical Navigable Small World): A graph-based indexing algorithm commonly used for high-dimensional nearest-neighbor search, which organizes data into a multi-layered structure for fast traversal.
  • Recall@10: A metric representing the proportion of relevant items (correct nearest neighbors) found within the top 10 results returned by a search.
  • Payload: Metadata attached to a vector (e.g., tags, categories, timestamps) used for filtering search results.
Original article

Filtered Vector Search: What ACORN Fixes, and What Fixes ACORN

Filtered vector search breaks when metadata filters turn a healthy nearest-neighbor graph into scattered islands. HNSW’s m parameter controls how many links each point gets. At Qdrant’s default m=16, the one-million-point collection benchmarked below averaged about 21 links per node on layer 0. Filter out 96% of the points and fewer than one link per node survives on average, so traversal can get stranded before it reaches the true nearest matches.

Qdrant repairs that damage in two places. Filterable HNSW adds extra edges at index time; ACORN steps through neighbors of neighbors at search time. Both run on the same collection. ACORN earns its cost where the extra edges don’t reach: values too common to link, AND filters no single field’s edges cover, and payload fields the build skipped silently.

This benchmark runs on a single Qdrant instance and compares four of Qdrant’s own search strategies over four builds.

The Two ACORNs

The ACORN paper (Patel et al., SIGMOD 2024) describes two algorithms. Its headline claim of “2-1,000x higher throughput at a fixed recall” belongs to ACORN-gamma, which expands neighbor lists during index construction at 8.8x to 33.1x plain HNSW’s build time in the paper’s own table.

ACORN-1 is lighter. It builds a standard HNSW graph, then checks neighbors of neighbors at search time where direct neighbors fail the filter. Qdrant implements ACORN-1 as a query parameter you opt into per request, with no index-time changes.

The Graph Qdrant Builds Instead

Filterable HNSW, which our co-founder Andrey Vasnetsov described in 2019, builds the repair into the index. When a payload field, the metadata attached to each point, is indexed, Qdrant adds extra HNSW edges between points that share a value in that field, so a filtered query keeps a connected graph to traverse. Qdrant gives those edges to payload fields at index time, and not every field earns them.

Those edges cost build time. On our one-million-point collection, the HNSW index built in 116 seconds without them and 507 to 652 seconds with them, 4.4x to 5.6x the cost. That range covers two builds at identical settings, so it is build-to-build variance. Both figures are index build time, with ingest excluded.

Qdrant builds those edges per payload field, never per combination, so an AND filter lands on an intersection that no single field’s edges cover. ACORN-1 covers that gap and pays at query time instead of build time. Qdrant’s query planner chooses automatically between ACORN, full scan, retrieval straight from the payload index, and filterable HNSW.

The Benchmark

The benchmark runs on one million deep-image-96 vectors, 96-dimensional image embeddings from the ANN-benchmarks suite. Keyword filters match from 20% of the points down to 0.012%. Recall@10 is scored against exact brute force over 500 queries per filter, and latency is mean server-side query time.

We tested four strategies:

  1. Plain graph: standard HNSW with no extra edges.
  2. Plain graph + ACORN: the same graph with ACORN forced on.
  3. Filterable HNSW: the default build with extra edges.
  4. Planner + ACORN: Qdrant’s default query planner, free to route each query to ACORN, full scan, or the payload index.

Every filter matches one keyword value on a payload field. The collection carries seven such fields, holding 5, 10, or 100 distinct values each.

Single Filters: Extra Edges Win

hnsw_ef, shortened to ef below, is the number of candidates the search evaluates, so raising it improves recall and slows the query. Selectivity is the fraction of points that pass the filter.

Filter (selectivity) Plain graph Plain graph + ACORN Filterable HNSW
One keyword (20%) 62.9% @ 1.6ms 98.9% @ 4.4ms 94.8% @ 1.2ms
One keyword (10%) 20.6% @ 1.7ms 98.1% @ 4.3ms 99.0% @ 1.1ms
One keyword (1%) 0.1% @ 1.6ms 67.7% @ 4.7ms 99.8% @ 1.0ms
Correlated (10%) 88.4% @ 1.7ms 98.6% @ 3.5ms 99.0% @ 1.2ms

Why Some Payload Fields Get No Extra Edges

Qdrant builds extra edges by walking the values of each indexed payload field. For each value it finds the points that share it and links them, so a query filtered to that value still has a graph to traverse.

A value shared by more points than a size cap gets no extra edges, because the main graph should already keep that many points connected. Qdrant derives that cap per segment, the slice of a collection that has its own index. The formula is point count divided by average links per node, times four.

Field Distinct values Points per value Extra edges built
2 fields 5 ~200,000 No, all 5 values over the cap
2 fields 10 ~100,000 Yes, 10 of 10 values
Correlated field 10 ~100,000 Yes, 10 of 10 values
2 fields 100 ~10,000 Yes, 100 of 100 values

Double Filters: The Intersection Gap

The same benchmark at hnsw_ef=64, now with an AND filter over two keyword fields.

Filter (selectivity) Plain graph + ACORN Filterable HNSW Planner + ACORN
Two keywords (4%) 95.2% @ 7.7ms 63.7% @ 1.2ms 99.9% @ 13.9ms
Two keywords (1%) 72.7% @ 6.8ms 70.8% @ 1.5ms 100% @ 3.7ms
Two keywords (0.012%) 0.6% @ 2.6ms 1.8% @ 2.6ms 100% @ 1.3ms

ACORN on a Normal Collection

This is the default configuration: extra edges, the default threshold, and the planner free to choose the graph or the payload index in both columns.

Filter (selectivity) Planner, ACORN off Planner + ACORN
One keyword (20%) 90.8% @ 1.1ms 100% @ 5.7ms
One keyword (10%) 98.6% @ 0.9ms 99.9% @ 4.4ms
One keyword (1%) 100% @ 1.7ms 100% @ 1.6ms
Correlated (10%) 98.6% @ 1.0ms 100% @ 4.2ms
Two keywords (4%) 39.7% @ 1.1ms 100% @ 7.3ms
Two keywords (1%) 97.2% @ 2.1ms 100% @ 2.5ms
Two keywords (0.012%) 100% @ 1.4ms 100% @ 1.2ms

What to Measure on Your Own Collection

Measure recall for each filter shape you serve. Start with the ones most likely to break: values covering roughly a fifth of the collection or more, and AND combinations of them. Create a payload index on every field you filter on, and leave ACORN off to start. Then sample a few hundred real queries per filter shape. Compare the recall gain with the latency cost. Turning it on never lowered recall in any of our runs, so if you are unsure, the cost of leaving it on is latency.

Further Reading

Explore all 54 articles in today's digest

Fresh dev news, AI-digested daily. Never miss a trend at devoured.fyi