DEV Community

Ce Gao
Ce Gao

Posted on • Originally published at blog.pgvecto.rs

pgvecto.rs 0.2: Unifying Relational Queries and Vector Search in PostgreSQL

We are excited to announce the release of pgvecto.rs 0.2, a significant milestone in the journey of bridging the gap between relational queries and vector search in PostgreSQL. This update brings together the power of both worlds, offering enhanced efficiency and enabling complex queries within PostgreSQL.

In the past, developers and data scientists encountered the significant challenge of managing separate systems for relational queries and vector search. This resulted in increased complexity and resource overhead. However, with the release of pgvecto.rs 0.2, we have addressed this issue by integrating the cutting-edge VBASE method from OSDI 2023. This integration has substantially refined the efficiency of vector search within PostgreSQL.

Real-world applications: Immich

Real-world applications often require complex queries that go beyond simple Approximate Nearest Neighbor (ANN) search. To explore a practical example of such applications, let's take a closer look at immich, a self-hosted photo and video backup solution that highlights the importance of advanced vector and traditional relational queries.

immich leverages advanced vector-based and relational queries to provide intelligent search capabilities. With immich, you can efficiently search and discover relevant media files based on visual similarity, metadata, and user-defined tags. The underlying technology powering this functionality is pgvecto.rs.

We will provide a concise overview of the search feature in immich. Consider a scenario where our database consists of three tables.

CREATE TABLE AssetEntity (
  id UUID PRIMARY KEY,
  ownerId VARCHAR NOT NULL,
  createdAt TIMESTAMPTZ NOT NULL,
  updatedAt TIMESTAMPTZ NOT NULL,
  deletedAt TIMESTAMPTZ,
  isArchived BOOLEAN DEFAULT false,
  isVisible BOOLEAN DEFAULT true,
  ...
);

CREATE TABLE ExifInfo (
  id INT PRIMARY KEY,
  assetId UUID,
  lat FLOAT,
  long FLOAT,
  city VARCHAR(255),
  state VARCHAR(255),
  country VARCHAR(255),
  description TEXT,
  ...
);

CREATE TABLE ImageEmbedding (
  id INT PRIMARY KEY,
  assetId UUID,
  embedding vector(n), -- assuming 'n' is the dimensionality of the vector
  ...
);
Enter fullscreen mode Exit fullscreen mode

We have a table named AssetEntity that stores information about the images, including their unique identifier (id), the owner (ownerId), creation and update timestamps (createdAt and updatedAt), and other relevant attributes.

The ExifInfo table contains information specific to the EXIF data of the images, such as the latitude (lat), longitude (long), city, state, country, and description. The assetId column in this table establishes a relationship with the asset_entity table.

Additionally, we have the ImageEmbedding table, which stores vector-based embeddings for each image. The embedding column is an array of floating-point numbers representing the image embedding vector. The assetId column in this table also establishes a relationship with the asset_entity table.

The query statement below is used to search for images based on certain criteria and sorting by the similarity of the image embeddings. It joins the AssetEntity, ImageEmbedding, and ExifInfo tables, filters the results based on criteria like ownerId, isArchived, isVisible, createdAt, and city in the EXIF info, then orders the images by the similarity of the provided embedding. The query returns a limited number of results based on the specified limit.

SELECT a.*, e.*, e.*
FROM AssetEntity AS a
INNER JOIN ImageEmbedding AS e ON e.assetId = a.id
LEFT JOIN ExifInfo AS e ON e.assetId = a.id
WHERE a.ownerId IN (:userIds)
  AND a.isArchived = false
  AND a.isVisible = true
  AND a.createdAt < NOW()
  AND e.city = :city
ORDER BY s.embedding <=> :embedding
LIMIT :numResults;
Enter fullscreen mode Exit fullscreen mode

It can be seen as a scenario involving Single-Vector TopK + Filter + Join operations. The limitations of pgvector in supporting such operations highlight the need for VBASE.

When it comes to Single-Vector TopK operations, pgvector falls short in providing efficient performance. TopK queries require finding the K nearest neighbors to a target vector, but pgvector struggles to predict the optimal value of K, leading to suboptimal query performance. VBASE, on the other hand, addresses this limitation by leveraging relaxed monotonicity and offering significantly higher efficiency. It provides a more accurate and efficient solution for single-vector TopK queries.

Additionally, pgvector's support for Filter and Join operations in conjunction with vector queries is limited. Complex queries that involve filtering or joining on both scalar and vector data can be challenging to execute efficiently in pgvector. VBASE, however, is designed to handle these types of queries seamlessly. It integrates vector search systems with relational databases, allowing for the execution of complex queries involving filters and joins on both scalar and vector attributes. This capability makes VBASE a more suitable choice for applications that require these operations.

Benchmark

To evaluate the performance, benchmarks can be conducted to measure the efficiency and effectiveness of both systems. We utilize the laion-768-5m-ip-probability dataset for benchmarking purposes due to the absence of a comprehensive relational benchmark. The dataset is derived from LAION 2B images. It contains 5,000,000 vectors, 10,000 queries.

The dataset includes a probability column that stores random floating-point values generated from a uniform distribution between 0 and 1. The ratio of 0.01 means that each query covers 1% (or 0.01 times) of the dataset, allowing for focused analysis.

We present the recall, latency (in milliseconds), and RPS (requests per second) for various probability ranges while keeping the ef_search constant. The ef_search parameter represents the size of the list utilized during k-NN (k-Nearest Neighbors) searches, determining the trade-off between search accuracy and query processing time.

pgvecto.rs, when used with VBASE, consistently yields improved recall, particularly when working with low probability values.

Other features

pgvecto.rs 0.2 introduces the following key features and improvements other than VBASE integration:

  • FP16: Users can now store embeddings in PostgreSQL using half the float32 size, significantly improving latency. This optimization has a negligible impact on final recall, less than 1%.

  • Asynchronous indexing: Insertion operations are non-blocking, ensuring a smoother and more efficient data insertion and indexing process.

  • Doubled query performance: pgvecto.rs 0.2 offers query performance that is twice as fast as the previous version (0.1), marking a significant leap forward in system efficiency.

  • Observability: The new pg_vector_index_stat view provides a transparent view into the indexing internals of pgvecto.rs. Users can monitor index construction, configuration adjustments, and detailed statistical analysis in real time, fostering a more intuitive and controlled environment.

Quick start

To get started with pgvecto.rs 0.2, you could run it in a docker container:

docker run \
  --name pgvecto-rs-demo \
  -e POSTGRES_PASSWORD=mysecretpassword \
  -p 5432:5432 \
  -d tensorchord/pgvecto-rs:pg16-v0.2.0
Enter fullscreen mode Exit fullscreen mode

Please check out our documentation for more details. We encourage you to try out pgvecto.rs, benchmark it against your workloads, and contribute your indexing innovations. Join our Discord community to connect with the developers and other users working to improve pgvecto.rs!

Top comments (0)