Metadata Filtering: The basics
Metadata filtering lets you restrict a nearest-neighbor search to only points that satisfy conditions on stored fields—e.g. category = "news", date > 2024-01-01. You get the top similar vectors within that subset, which is essential for multi-tenant, faceted, or time-scoped search in a vector database. This topic covers pre- vs. post-filtering, filter types, and implementation.
Summary
- Restrict nearest-neighbor search to points satisfying conditions (e.g.
category = "news",date > 2024-01-01). Essential for multi-tenant, faceted, time-scoped search. - Metadata in payloads or columns; query = vector + filter. Pre-filtering restricts before/during traversal (efficient, selective); post-filtering runs search then drops non-matching (simpler, may need extra candidates). Pre-filter is harder with ANN.
- Filter types: equality, range, Boolean (AND, OR, NOT). Often implemented with bitmaps/bitsets for fast combination with index traversal.
- Trade-off: pre-filter saves work and improves latency when selective but is harder with ANN; post-filter is simple but may require over-fetching.
- Practical tip: index only fields you filter on; use columnar or bitmap-backed filters for hot predicates; request more than k candidates when using post-filter with selective conditions.
Pre-filtering vs. post-filtering
The metadata lives in payloads or columns alongside each vector. At query time you pass both a query vector and a filter expression. How the filter is applied depends on the implementation: pre-filtering restricts the set before or during index traversal (only eligible points are considered); post-filtering runs the vector search first and then drops results that don’t match the filter.
Pre-filtering is more efficient when the filter is selective but is harder to implement with ANN indexes; post-filtering is simple but may require fetching extra candidates to fill the result set. Pipeline (pre-filter): build eligible set from filter (e.g. bitmap) → intersect with index traversal so only eligible points are scored → return top-k. Pipeline (post-filter): run ANN over full set → apply filter to results → if fewer than k, may need to request more candidates and re-run or over-fetch upfront.
Filter types and implementation
Common filter types include equality (e.g. user_id = "abc"), range (e.g. price < 100), and Boolean combinations (AND, OR, NOT). Support for schemaless or nested JSON varies by VDB. Filtering is often implemented using bitmaps or bitsets so that the eligible set can be combined quickly with the index traversal.
Trade-off: equality and range on indexed columns are fast; complex or schemaless predicates may fall back to post-filter or scan. Practical tip: define and index the filter fields you need; use Boolean AND/OR to combine conditions; for very selective filters with post-filter, set a higher top_k or use a parameter (e.g. oversample) so you get enough results after filtering.
Frequently Asked Questions
What is the difference between pre-filtering and post-filtering?
Pre-filtering restricts the candidate set before or during index traversal so only eligible points are considered. Post-filtering runs vector search first, then filters results. Pre-filter is more efficient when selective but harder with ANN; post-filter may require over-fetching to fill the result set.
Can I filter on multiple fields?
Yes. Use Boolean expressions (AND, OR, NOT) to combine conditions. Support varies by VDB; check docs for nested or schemaless fields.
Does filtering affect recall?
Pre-filtering can reduce the candidate set so that the ANN search runs on a smaller subset; recall is over that subset. Post-filtering runs full ANN then drops non-matching—if the filter is very selective, you may need to request more than k candidates to get k results after filtering. See how metadata cardinality affects query performance.
Which metadata fields should I index?
Index fields you filter on frequently. Unindexed fields can often be returned with results but not used in filter predicates. Columnar or bitmap indexes on filter columns speed up pre-filtering.