By default, you cannot capture all pgvecto.rs logs. pgvecto.rs starts a background worker process for indexing, and it prints logs to standard error. To capture
Logging
By default, you cannot capture all pgvecto.rs logs. pgvecto.rs starts a background worker process for indexing, and it prints logs to standard error. To capture them, you need to set logging_collector to on. You can get more information from PostgreSQL document about logging collector.
You can set logging_collector to on with the following command:
psql -U postgres -c 'ALTER SYSTEM SET logging_collector = on;'# You need restart the PostgreSQL cluster to take effects.sudo systemctl restart postgresql.service # for pgvecto.rs running with systemddocker restart pgvecto-rs-demo # for pgvecto.rs running in docker
Index configuration
since v0.3.0
For each index, there are a number of configuration items that are variable. Unlike options, they support real-time modification after the index has been created. These items can be configured by function alter_vector_index.
By default, each vector index is optimized by only one thread at the backend. However, if you have multiple idle CPUs and want to take advantage of them, you can increase the number of threads.
Set the key argument to optimizing.threads and the value argument to the desired number of threads.
-- alter_vector_index(dim: OID, key = 'optimizing.threads', value: TEXT as INT[1-65535])
SELECTalter_vector_index('table_col_idx'::regclass::oid,'optimizing.threads','4');
2 - Upgrading
If you update the extension to a new version, let’s say it’s a.b.c. This command helps you to update the schema of extension:
General Steps
If you update the extension to a new version, let’s say it’s a.b.c. This command helps you to update the schema of extension:
ALTEREXTENSIONvectorsUPDATE;-- or
ALTEREXTENSIONvectorsUPDATETO'a.b.c';
You may get this error if some indexes were created before upgrading pgvecto.rs to 0.4.0:
ERROR: index public.this_is_index depends on operator class vector_cos_ops for access method vectors
index public.this_is_index depends on operator class vector_cos_ops for access method vectors cannot drop operator class vector_cos_ops for access method vectors because other objects depend on it
ERROR: cannot drop operator class vector_cos_ops for access method vectors because other objects depend on it
SQL state: 2BP01
Detail: index public.that_is_also_index depends on operator class vector_cos_ops for access method vectors
index public.that_is_also_index depends on operator class vector_cos_ops for access method vectors
Hint: Use DROP ... CASCADE to drop the dependent objects too.
You can simply drop these indexes, and then upgrade the extension:
DROPINDEXthis_is_index;DROPINDEXthat_is_also_index;ALTEREXTENSIONvectorsUPDATE;-- CREATE INDEX this_is_index ...
-- CREATE INDEX that_is_also_index ...
Upgrade from 0.1.x
You need to follow these steps to make ALTER EXTENSION vectors UPDATE work.
Let’s assume your pgvecto.rs version is 0.1.x (replace x with a number).
pgvecto.rs is installed in schema vectors from 0.2.0, you may need to set search_path for the database.
3 - Logical replication
Logical replication is a feature in PostgreSQL that enables the replication of individual database objects or a subset of data from one PostgreSQL database to a
Logical replication is a feature in PostgreSQL that enables the replication of individual database objects or a subset of data from one PostgreSQL database to another.
With logical replication, you can selectively replicate specific tables, databases, or even specific rows based on predefined replication rules. This provides more flexibility compared to physical replication, where the entire database cluster is replicated. It allows you to design custom replication topologies and replicate only the data that is necessary for your use case.
We will show you how to use logical replication to replicate data from one PostgreSQL database to another.
Now, we can set logical replication between source database and target database.
Prepare test data
We need to create a table named test with a column named embedding of type vector(10) in source database and target database. Then we create an index on the embedding column of the test table in source database and target database. Finally, we insert data into the source database.
We create an index on the embedding column of the test table in source database and target database. The index type is flat, it is a brute force algorithm. We choose vector_l2_ops squared Euclidean distance to measure the distance between vectors. Another index type and distance function can be found in here.
To simplify the process of setting up logical replication between two PostgreSQL databases, we will use pg-easy-replicate.
We use pg-easy-replicate to set up logical replication between source database and target database.
# get the network name$ docker network ls | grep pg
8631dd77129b pg_regress_localnet bridge local# get source and target container ip$ docker inspect <container_id> | grep IP
$ docker run -e SOURCE_DB_URL="postgres://postgres:password@<source_db_ip>:5432/postgres" -e TARGET_DB_URL="postgres://postgres:password@<target_db_ip>:5432/postgres" -it --rm --network=<network> shayonj/pg_easy_replicate:latest pg_easy_replicate config_check
/usr/bin/pg_dump
✅ Config is looking good.
Bootstrap
Every sync will need to be bootstrapped before you can set up the sync between two databases. Bootstrap creates a new super user to perform the orchestration required during the rest of the process. It also creates some internal metadata tables for record keeping.
Once the bootstrap is complete, you can start the sync. Starting the sync sets up the publication, subscription and performs other minor housekeeping things.
Now we can query the target database to get the nearest neighbor of a vector in the embedding column of the test table. The result is the same as the source database.
Foreign data wrapper(FDW) is an extension in PostgreSQL that allows you to access and query data stored in remote databases as if they were local tables. FDW pr
Foreign data wrapper(FDW) is an extension in PostgreSQL that allows you to access and query data stored in remote databases as if they were local tables. FDW provides a way to integrate and interact with different data sources.
With the FDW extension, you can define foreign tables in your local PostgreSQL database that mirror the structure of tables in remote databases. These foreign tables act as proxies or wrappers for the remote data, enabling you to perform SELECT, INSERT, UPDATE, and DELETE operations on them, just like regular tables in PostgreSQL.
In this tutorial, we will use the postgres_fdw module, which includes the foreign-data wrapper. This wrapper can be used to access data stored in external PostgreSQL servers. This article will explain how to use postgres_fdw to access index data in a foreign PostgreSQL cluster that already has the pgvecto.rs extension installed.
Deploy local and foreign PostgreSQL clusters
In this tutorial, we will use docker compose to deploy two PostgreSQL clusters.
# create extension postgres_fdw in local db$ psql -h <local_db_ip> -U postgres -p 5432DROP EXTENSION IF EXISTS postgres_fdw;CREATE EXTENSION postgres_fdw;# create extension vectors in foreign db$ psql -h <foreign_db_ip> -U postgres -p 5432DROP EXTENSION IF EXISTS "vectors";CREATE EXTENSION "vectors";
Foreign database operations
First, we need create a table test and build an index on it in the foreign db. The test table has two columns: id and embedding. The embedding column is a vector column, and its type is vector(10). The id column is the primary key of the test table.
We create an index on the embedding column of the test table. The index type is flat, it is a brute force algorithm. We choose vector_l2_ops squared Euclidean distance to measure the distance between vectors. Another index type and distance function can be found in here.
In local database, we need to create a table local and a foreign server foreign_server. The local table has two columns: id and name. The id column is the primary key of the local table. The foreign_server is a foreign server, which is used to access the foreign db.
Use the CREATE USER MAPPING statement to create a mapping between remote users and local users, requiring the username and password of the remote user.
Use the CREATE FOREIGN TABLE statement to create a remote table. It is important to note that the types of each column should match those of the actual remote table, and it’s best to keep the column names consistent. Otherwise, you will need to use the column_name parameter to specify the column name in the remote table for each individual column.
If you want to use pgvecto.rs in PostgreSQL which is running in Kubernetes, we provide a tutorial to help you. In this tutorial, we will use CloudNative-PG to d
If you want to use pgvecto.rs in PostgreSQL which is running in Kubernetes, we provide a tutorial to help you. In this tutorial, we will use CloudNative-PG to deploy PostgreSQL cluster in Kubernetes.
We use CloudNative-PG (cnpg) to deploy PostgreSQL cluster in Kubernetes. You can install it by helm.
$ sudo helm repo add cnpg https://cloudnative-pg.github.io/charts
$ sudo helm upgrade --install cnpg --namespace cnpg-system --create-namespace cnpg/cloudnative-pg
$ helm list --all-namespaces
NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION
cnpg cnpg-system 1 2024-01-02 08:17:11.661297545 +0000 UTC deployed cloudnative-pg-0.20.0 1.22.0
$ kubectl get pod -n cnpg-system
NAME READY STATUS RESTARTS AGE
cnpg-cloudnative-pg-67ff4f5f66-94m8d 1/1 Running 0 1m
Build PostgreSQL image with pgvecto.rs
We use the official CloudNative-PG docker image as the base image, and install pgvecto.rs in it. And you can also find pgvecto.rs version from releases.
# syntax=docker/dockerfile-upstream:masterARG CNPG_TAGFROMghcr.io/cloudnative-pg/postgresql:$CNPG_TAGARG CNPG_TAGARG PGVECTORS_TAGARG TARGETARCH# drop to root to install packagesUSERroot# install pgvecto.rsADD https://github.com/tensorchord/pgvecto.rs/releases/download/$PGVECTORS_TAG/vectors-pg${CNPG_TAG%.*}_${PGVECTORS_TAG#"v"}_$TARGETARCH.deb ./pgvectors.debRUN apt install ./pgvectors.debUSERpostgres
Notice: PostgreSQL docker image tag must start with CNPG_TAG for cloudnative-pg to recognize the postgres version.
Create PostgreSQL cluster
We provide a sample yaml file to create a PostgreSQL cluster in Kubernetes. You can modify it according to your needs. You need pay attention to the following points:
Set shared_preload_libraries to load pgvecto.rs shared library. You can also set postInitApplicationSQLALTER SYSTEM SET shared_preload_libraries = "vectors.so"; to load pgvecto.rs shared library.
Execute CREATE EXTENSION IF NOT EXISTS "vectors"; to create vectors extension.
apiVersion:v1kind:Secretmetadata:name:tensorchordtype:kubernetes.io/basic-authdata:password:dGVuc29yY2hvcmQ=# tensorchord username:dGVuc29yY2hvcmQ=# tensorchord---apiVersion:postgresql.cnpg.io/v1kind:Clustermetadata:name:pgvectors spec:instances:1bootstrap:initdb:database:tensorchordpostInitApplicationSQL:- CREATE EXTENSION IF NOT EXISTS "vectors";owner:tensorchordsecret:name:tensorchorddataChecksums:trueencoding:'UTF8'storage:size:1GiimageName:<your-postgresql-image-repo>:<pg-tag>postgresql:shared_preload_libraries:# load pgvecto.rs shared library- "vectors.so"
You can install cnpgkubectl plugin to manage your PostgreSQL cluster. Now we can check the status of the cluster.
$ sudo kubectl get pod
pgvectors-1 1/1 Running 0 3m54s
$ kubectl cnpg status pgvectors
Cluster Summary
Name: pgvectors
Namespace: default
System ID: 7323107530735296538PostgreSQL Image: docker.io/xieydd/pgvectors:15
Primary instance: pgvectors-1
Primary start time: 2024-01-12 07:17:34 +0000 UTC (uptime 17m33s)Status: Cluster in healthy state
Instances: 1Ready instances: 1Current Write LSN: 0/4000000 (Timeline: 1 - WAL File: 000000010000000000000003)Certificates Status
Certificate Name Expiration Date Days Left Until Expiration
---------------- --------------- --------------------------
pgvectors-ca 2024-04-11 07:12:00 +0000 UTC 89.98
pgvectors-replication 2024-04-11 07:12:00 +0000 UTC 89.98
pgvectors-server 2024-04-11 07:12:00 +0000 UTC 89.98
Continuous Backup status
Not configured
Physical backups
No running physical backups found
Streaming Replication status
Not configured
Unmanaged Replication Slot Status
No unmanaged replication slots found
Managed roles status
No roles managed
Tablespaces status
No managed tablespaces
Instances status
Name Database Size Current LSN Replication role Status QoS Manager Version Node
---- ------------- ----------- ---------------- ------ --- --------------- ----
pgvectors-1 29 MB 0/4000000 Primary OK BestEffort 1.22.0 kind-control-plane
Notice: This article just provides a minimal configuration, not include logical replication, streaming logical replication, backup and restore, etc. We will provide those in another article. You can also refer to CloudNative-PG for more Cluster configuration.
Connect to PostgreSQL cluster
You can use kubectl port-forward to connect to PostgreSQL cluster.
$ kubectl port-forward services/pgvectors-rw 5432:5432
$ psql -h 127.0.0.1 -d tensorchord -U tensorchord
tensorchord=> \dx
Name | Version | Schema | Description
---------+---------+------------+----------------------------------------------------------------------------------------------
plpgsql | 1.0 | pg_catalog | PL/pgSQL procedural language
vectors | 0.1.13 | public | vectors: Vector database plugin for Postgres, written in Rust, specifically designed for LLM
The vectors extension is installed successfully. You can try quick-start without installation.
6 - Migration
When migrating from pgvector to PGVecto.rs, it is possible that you may have a table with a column of vector type. An example of this would be:
outline: [2,3]
PGVecto.rs Migration Overview
From pgvector
Prerequisites
When migrating from pgvector to PGVecto.rs, it is possible that you may have a table with a column of vector type. An example of this would be:
This is a typical scenario when pgvector is used. If the following requirements are met, the migration can be initiated.
Please note that your pgvector extension is not installed in the vectors schema. This means that you can install pgvector and PGVecto.rs at the same time.
Steps to Migration
1. Install PGVecto.rs
Please follow the instructions provided to install PGVecto.rs and ensure that the extension is loaded by PostgreSQL.
CREATEEXTENSIONvectors;
The two extensions, pgvector and PGVecto.rs, are now installed at the PostgreSQL.
To validate the install, please run \dx in psql. You will see that there is an extension called vector for pgvector and another called vectors for PGVecto.rs.
postgres=# \dx List of installed extensions
Name | Version | Schema | Description
---------+---------+------------+----------------------------------------------------------------------------------------------
plpgsql | 1.0 | pg_catalog | PL/pgSQL procedural language
vector | 0.7.2 | public | vector data type and ivfflat and hnsw access methods
vectors | 0.3.0 | vectors | vectors: Vector database plugin for Postgres, written in Rust, specifically designed for LLM
Please note that there are some symbols with the same name in both extensions. This may cause confusion when doing the migration. To differentiate between the two, please verify that the search_path does not include the PGVecto.rs schema vectors.
SHOWsearch_path;-- if it shows: `"$user", public` -> This is okay
-- if it shows: `"$user", public, vectors` -> Remove `vectors` by:
SETsearch_path="$user, public";
2. Check existing indexes
For indexes created at vector columns, please retrieve the definition and record it in a convenient location. This information is necessary for the recovery of the indexes at a later stage.
To migrate from a pgvector vector column, the first step is to create a PGVecto.rs vector column of the corresponding type. The subsequent step is to replicate the vector data from the original column to the new one.
Here provides the conversion path for each vector type of pgvector:
bit -> text[] -> real[] -> vector(PGVecto.rs) -> bvector
This vector type is not supported for migration yet:
sparsevec
Method 1: Conversion after validation
With this method, you can check the correctness of the vector data during the migration process, and you do not need to worry about the indexes that have been created on the vector columns, as they will be automatically deleted.
However, it requires additional memory to store the vectors before and after the migration.
Warning
This step will cause some downtime, due to:
a short ACCESS EXCLUSIVE lock by ALTER TABLE ADD COLUMN
a much longer ROW EXCLUSIVE lock by UPDATE
a short ACCESS EXCLUSIVE lock by ALTER TABLE DROP COLUMN
-- From vector type
ALTERTABLEitemsADDCOLUMNmigrate_embeddingvectors.vector(3);UPDATEitemsSETmigrate_embedding=embedding::real[]::vectors.vector;-- From halfvec type
ALTERTABLEitemsADDCOLUMNmigrate_embeddingvectors.vecf16(3);UPDATEitemsSETmigrate_embedding=embedding::vector::real[]::vectors.vector::vectors.vecf16;-- For bit type
ALTERTABLEitemsADDCOLUMNmigrate_embeddingvectors.bvector(3);UPDATEitemsSETmigrate_embedding=string_to_array(embedding::text,NULL)::real[]::vectors.vector::vectors.bvector;
Once the data has been copied, you can check the data by SELECT and replace the existing column with the new one.
With this method, the migration will be completed in one command and no additional memory is required.
However, you need to delete the index on the vector column in advance.
Warning
This step will cause some downtime, due to:
a long ACCESS EXCLUSIVE lock by ALTER TABLE ALTER COLUMN
-- The name of index is from step 2
DROPINDEXIFEXISTSitems_embedding_idx;-- From vector type
ALTERTABLEitemsALTERCOLUMNembeddingTYPEvectors.vector(3)USINGembedding::real[]::vectors.vector;-- From halfvec type
ALTERTABLEitemsALTERCOLUMNembeddingTYPEvectors.vecf16(3)USINGembedding::vector::real[]::vectors.vector::vectors.vecf16;-- For bit type
ALTERTABLEitemsALTERCOLUMNembeddingTYPEvectors.bvector(3)USINGstring_to_array(embedding::text,NULL)::real[]::vectors.vector::vectors.bvector;
4. Recreate index
To recreate index on vector columns for PGVecto.rs , please enable the compatibility mode and create it like before.
SETvectors.pgvector_compatibility=on;-- Execute the command you get in step 2
CREATEINDEXitems_embedding_idxONpublic.itemsUSINGhnsw(embeddingvector_l2_ops);
For other vector types, such as halfvec, sparsevec, and bit, please refer to the indexing. Currently, pgvector_compatibility mode is not supported for these types.
5. Clean the environment
You may now safely remove the pgvector extension if it is no longer required.
DROP extension vector;
In the event that the pgvector extension is removed, it is advisable to reset the search_path in order to ensure that symbols in PGVecto.rs are accessible globally.
SETsearch_path="$user, public, vectors";-- or globally
ALTERSYSTEMSETsearch_path="$user, public, vectors";
Verify the result
Once the migration task is executed, you can verify the new columns by SELECT SQL.