New Superpower Unlocked: Conditional Filtering in the pgvecto.rs
open source
Aug 25, 2023

New Superpower Unlocked: Conditional Filtering in the pgvecto.rs

Jinjing Zhou
Co-founder
Usamoi
pgvecto.rs Developer

Introduction

In our previous post "Do we really need a specialized vector database?", we discussed how the inability to filter has been a key factor pushing users towards dedicated vector search engines.

Today, we are glad to eliminate that tradeoff by becoming the first to enable conditional filtering directly on HNSW indexes within a relational database. With this breakthrough advancement, pgvecto.rs enables comprehensive filtering capability directly within vector search, unlocking new possibilities for conditional logic during similarity lookups in PostgreSQL.

We welcome you to leverage pgvecto.rs with conditional filtering for your production workloads. The performance and flexibility open up new possibilities for integrating vector search into real-world applications.

Get Started

It's easy to add conditional filtering to your pgvecto.rs vector similarity queries. Simply include a WHERE clause with the ORDER BY clause to filter vectors with the approximate search.

For example, to find the top 5 similar items to the vector 1,2,3 but only for category 1:

SELECT * 
FROM items
WHERE category_id = 1
ORDER BY embedding <-> '[1,2,3]' 
LIMIT 5;

The WHERE clause filters the items table to only category 1 before vector similarity matching. This returns the most relevant results for that category.

You can filter by any criteria and combine conditional filtering with other PostgreSQL clauses. The filters leverage PostgreSQL's indexes for speed.

Implementation Internals

pgvecto.rs implements conditional filtering using a pre-filtering approach optimized for HNSW indexes.

When a conditional filter is applied, a vector similarity search proceeds through the HNSW index to locate potential matching candidates based on the index topology. As candidates are identified, they are checked against the filter criteria by leveraging PostgreSQL's native indexing capabilities before being added to the result set. Only candidates that satisfy the filters are included. This allows pruning the raw HNSW results on-the-fly based on the specified filters. Candidates that don't meet the conditions are excluded without needing an explicit allow-list.

The search still adheres to the normal HNSW exit conditions, concluding when limits are hit and results no longer improve.

By evaluating filters in real-time using PostgreSQL indexes during the HNSW traversal, pgvecto.rs combines the speed of approximate search with the precision of exact conditional logic.

Performance

To validate conditional filtering performance in pgvecto.rs, we benchmarked against Qdrant and Weaviate using the filtered search benchmark from Qdrant on range-2048-filter dataset. We ran the benchmark on GCP's n2-standard-8, which has 8 cores and 32GB memory.

pgvecto.rs qdrant weaviate
Search ef Precision RPS Precision RPS Precision RPS
64 0.500228 59.096738 0.46660 538.409163 0.730032 15.352193
128 0.605808 47.560120 0.60050 402.074513 0.773788 15.629299
256 0.642750 92.821136 0.72787 281.051626 0.822596 15.545560
512 0.751090 49.780314 0.83303 180.936436 0.871468 15.448074
Benchmark (Source code can be found here)

In our preliminary testing, currently pgvecto.rs is faster than Weaviate but slower than Qdrant. Qdrant utilizes a filtered HNSW structure directly in the index, whereas we implemented pre-filtering. This indicates potential areas for future optimization.

As this is the first iteration of our implementation, pgvecto.rs does not yet include optimizations like automatic query planning, post filtering, and flat search for tight filters. For now, it may not always outperform brute-force search without the vector index. Specifically, on smaller datasets or with lower dimension vectors, scanning and filtering the table directly can sometimes be faster than using the vector index. We have plans to incorporate these optimization techniques soon which should provide significant speedups and choose the optimal strategy automatically.

There are also opportunities to explore building filtered HNSW structures like Qdrant for even faster performance. Overall this is just the beginning, and we expect pgvecto.rs filtering to become industry-leading with further development.

We Love Rust and PostgreSQL

A key ingredient enabling the development of pgvecto.rs is our use of the Rust programming language alongside PostgreSQL. Rust's performance, safety, and concurrency make it an ideal language for building the core algorithms and data structures of pgvecto.rs efficiently. The abstractions Rust provides facilitate clean integration with PostgreSQL without compromising speed. PostgreSQL gives us a robust, production-ready database to extend using Rust. Its extensibility and indexing capabilities are critical for pgvecto.rs.

We also want to thank the pgrx project for enabling the creation of PostgreSQL extensions in Rust. Pgrx made it seamless to leverage Rust's strengths in pgvecto.rs.

Together, Rust and PostgreSQL are a perfect match that helped us develop pgvecto.rs from prototype to production. We love these technologies and are proud to contribute.

Future plan

For now, we are extremely excited to have delivered the foundational filtering capability that makes pgvecto.rs an indispensable vector search tool. We're also planning to support product quantization with HNSW and more index type like DiskANN. Stay tuned as we rapidly iterate to make it faster and more robust!