跳转到主要内容

这是本节的多页打印视图。 .

返回本页常规视图.

运维管理

pgvecto.rs 的配置、升级、逻辑复制、FDW、Kubernetes 部署与迁移指南。

1 - 配置

默认情况下无法捕获所有 pgvecto.rs 日志。pgvecto.rs 会启动后台工作进程进行索引构建并将日志输出到标准错误,需要开启 logging_collector 来捕获日志。

日志配置

默认情况下,你无法捕获 pgvecto.rs 的全部日志。pgvecto.rs 会启动一个后台工作进程(Background Worker)来构建索引,并将日志输出到标准错误(stderr)。若要捕获这些日志,你需要将 logging_collector 设置为 on。更多详情可参阅 PostgreSQL 关于日志收集器的官方文档。

你可以通过以下命令将 logging_collector 设置为 on:

psql -U postgres -c 'ALTER SYSTEM SET logging_collector = on;'
# 需要重启 PostgreSQL 集群以使配置生效。
sudo systemctl restart postgresql.service   # 适用于通过 systemd 运行的 pgvecto.rs
docker restart pgvecto-rs-demo  # 适用于在 Docker 中运行的 pgvecto.rs

索引配置

自 v0.3.0 起

对于每个索引,都有若干可动态调整的配置项。与创建时的静态选项(options)不同,这些配置项支持在索引创建后进行实时修改。你可以通过 alter_vector_index 函数来修改这些配置项。

-- alter_vector_index(dim: OID, key: TEXT, value: TEXT)
SELECT alter_vector_index('index_name'::regclass::oid, 'configuration_name', 'value');

目前支持的所有配置项如下:

后端优化线程数

默认情况下,每个向量索引在后端仅由一个线程执行优化。如果你有多个空闲 CPU 核心并希望充分利用它们,可以增加优化线程的数量。

将 key 参数设置为 optimizing.threads,并将 value 参数设置为期望的线程数:

-- alter_vector_index(dim: OID, key = 'optimizing.threads', value: TEXT as INT[1-65535])
SELECT alter_vector_index('table_col_idx'::regclass::oid, 'optimizing.threads', '4');

2 - 版本升级

如何将 pgvecto.rs 扩展升级到新版本并更新扩展 Schema 与索引。

通用步骤

如果你将扩展更新到了新版本(假设版本号为 a.b.c),可以使用以下命令更新扩展的 Schema:

ALTER EXTENSION vectors UPDATE;
-- 或
ALTER EXTENSION vectors UPDATE TO 'a.b.c';

如果你是从 0.1.x 版本升级,请先阅读从 0.1.x 升级。

如果你要升级到 0.4.0 版本,请阅读升级到 0.4.0。

随后执行以下 SQL,它会协助完成必要的维护工作:

SELECT pgvectors_upgrade();

你需要重启 PostgreSQL 实例以使更改生效。

你可以通过以下命令查看所有向量索引的状态:

SELECT
        I.relname AS indexname
    FROM pg_index X JOIN
         pg_class I ON I.oid = X.indexrelid JOIN
         pg_am A ON A.oid = I.relam
    WHERE A.amname = 'vectors';

假设输出如下:

 indexname
-------------
 t_val_idx_1
 t_val_idx_2

然后你可以重建所有向量索引:

REINDEX INDEX t_val_idx_1;
REINDEX INDEX t_val_idx_2;

升级到 0.4.0

如果在将 pgvecto.rs 升级到 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.

你只需先删除这些索引,然后再升级扩展并重建索引即可:

DROP INDEX this_is_index;
DROP INDEX that_is_also_index;

ALTER EXTENSION vectors UPDATE;

-- CREATE INDEX this_is_index ...
-- CREATE INDEX that_is_also_index ...

从 0.1.x 升级

你需要按照以下步骤操作,才能使 ALTER EXTENSION vectors UPDATE 正常工作。

假设你当前的 pgvecto.rs 版本为 0.1.x(请将 x 替换为实际的数字):

CREATE SCHEMA IF NOT EXISTS vectors;
UPDATE pg_catalog.pg_extension SET extversion = '0.1.x' where extname = 'vectors';
UPDATE pg_catalog.pg_extension SET extrelocatable = true where extname = 'vectors';
ALTER EXTENSION vectors SET SCHEMA vectors;
UPDATE pg_catalog.pg_extension SET extrelocatable = false where extname = 'vectors';
ALTER EXTENSION vectors UPDATE;
提示

从 0.2.0 版本开始,pgvecto.rs 安装在 vectors Schema 下,你可能需要为数据库配置 search_path。

3 - 逻辑复制

逻辑复制是 PostgreSQL 的一项特性,支持将单个数据库对象或数据子集从一个 PostgreSQL 数据库复制到另一个 PostgreSQL 数据库。

逻辑复制(Logical Replication)是 PostgreSQL 的一项特性,支持将单个数据库对象或数据子集从一个 PostgreSQL 数据库复制到另一个数据库。

借助逻辑复制,你可以根据预定义的复制规则,有选择地复制特定的表、数据库甚至特定的行。与复制整个数据库集群的物理复制相比,逻辑复制提供了更高的灵活性,允许你设计自定义的复制拓扑结构,并仅复制业务所需的数据。

下面我们将演示如何使用逻辑复制将向量数据从一个 PostgreSQL 数据库复制到另一个数据库。

部署源端和目标端 PostgreSQL 集群

$ echo 'version: "3.7"
services:
  source_db:
    image: tensorchord/pgvecto-rs:pg15-v0.2.0
    ports:
      - "5432:5432"
    environment:
      POSTGRES_PASSWORD: password
    command: >
      -c wal_level=logical
      -c shared_preload_libraries=vectors.so
    networks:
      localnet:

  target_db:
    image: tensorchord/pgvecto-rs:pg15-v0.2.0
    ports:
      - "5433:5432"
    environment:
      POSTGRES_PASSWORD: password
    command: >
      -c wal_level=logical
      -c shared_preload_libraries=vectors.so
    networks:
      localnet:

networks:
  localnet:
' > docker-compose.yml

$ docker compose up -d

在源数据库和目标数据库中分别创建 vectors 扩展:

# create extension vectors
$ psql -h <source_db_ip> -U postgres -p 5432 
DROP EXTENSION IF EXISTS "vectors";
CREATE EXTENSION "vectors";

$ psql -h <target_db_ip> -U postgres -p 5432
DROP EXTENSION IF EXISTS "vectors";
CREATE EXTENSION "vectors";

配置逻辑复制

现在我们可以在源数据库和目标数据库之间配置逻辑复制。

准备测试数据

我们需要在源数据库和目标数据库中分别创建一张名为 test 的表,其中包含一个类型为 vector(10) 的 embedding 列。然后在源数据库和目标数据库的 test 表的 embedding 列上分别创建索引。最后,向源数据库中插入数据。

创建表

DROP TABLE IF EXISTS test;
CREATE TABLE test (id integer PRIMARY KEY, embedding vector(10) NOT NULL);

创建索引

我们在源数据库和目标数据库的 test 表的 embedding 列上创建索引。这里使用 flat(暴力搜索)索引类型,并选择 vector_l2_ops(欧氏距离平方)来度量向量之间的距离。其他索引类型和距离函数请参阅索引指南。

CREATE INDEX ON test USING vectors (embedding vector_l2_ops) WITH (options = "[indexing.flat]");

插入数据

我们只需要向源数据库插入数据,数据随后会同步到目标数据库。

INSERT INTO test
SELECT i, ARRAY[random(), random(),random(),random(),random(),random(),random(),random(),random()]::real[] 
FROM generate_series(1, 100) i;

现在你可以在源数据库中搜索 test 表 embedding 列的最近邻向量:

postgres=# SELECT id FROM test ORDER BY embedding <-> '[0.40671515, 0.24202824, 0.37059402, 0.50316447, 0.10779921, 0.80774295, 0.8879849, 0.31292745, 0.05584943, 0.8738258]' LIMIT 10;
 id 
----
 82
 69
 80
 22
 31
 20
 85
 97
 72
(10 rows)

此时如果查询目标数据库,结果将为空:

SELECT id FROM test ORDER BY embedding <-> '[0.40671515, 0.24202824, 0.37059402, 0.50316447, 0.10779921, 0.80774295, 0.8879849, 0.31292745, 0.05584943, 0.8738258]' LIMIT 10;
 id 
----
(0 rows)

设置逻辑复制

为了简化在两个 PostgreSQL 数据库之间配置逻辑复制的流程,我们将使用 pg-easy-replicate。

我们使用 pg-easy-replicate 在源数据库和目标数据库之间建立逻辑复制:

# 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)

在正式设置两个数据库之间的同步之前,每次同步都需要先执行初始化引导(Bootstrap)。Bootstrap 会创建一个新的超级用户来执行后续流程所需的编排操作,同时还会创建一些内部元数据表用于记录状态。

$ 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=pg_regress_localnet shayonj/pg_easy_replicate:latest pg_easy_replicate bootstrap --group-name database-cluster-1 --copy-schema

启动同步

Bootstrap 完成后,即可启动同步。启动同步会自动配置发布(Publication)、订阅(Subscription)并完成其他清理维护工作。

$ docker run -e SOURCE_DB_URL="postgres://postgres:password@192.168.64.2:5432/postgres"    -e TARGET_DB_URL="postgres://postgres:password@192.168.64.3:5432/postgres"   -it --rm --network=pg_regress_localnet shayonj/pg_easy_replicate:latest pg_easy_replicate start_sync --group-name database-cluster-1 

测试逻辑复制

查询验证

现在我们可以查询目标数据库,获取 test 表 embedding 列中向量的最近邻。查询结果与源数据库完全一致:

postgres=# SELECT id FROM test ORDER BY embedding <-> '[0.40671515, 0.24202824, 0.37059402, 0.50316447, 0.10779921, 0.80774295, 0.8879849, 0.31292745, 0.05584943, 0.8738258]' LIMIT 10;
 id 
----
 82
 69
 80
 22
 31
 20
 85
 97
 72
(10 rows)

更新索引

如果你向源数据库继续插入新数据,数据也会实时同步到目标数据库。向源数据库插入新数据:

INSERT INTO test
SELECT i, ARRAY[random(), random(),random(),random(),random(),random(),random(),random(),random()]::real[] 
FROM generate_series(101, 200) i;

在源数据库中查询:

postgres=# SELECT id FROM test ORDER BY embedding <-> '[0.40671515, 0.24202824, 0.37059402, 0.50316447, 0.10779921, 0.80774295, 0.8879849, 0.31292745, 0.05584943, 0.8738258]' LIMIT 10;
id  
-----
  82
 130
 145
  69
  80
 200
  22
  31
 182
 (10 rows)

在目标数据库中查询,将返回相同的结果:

postgres=# SELECT id FROM test ORDER BY embedding <-> '[0.40671515, 0.24202824, 0.37059402, 0.50316447, 0.10779921, 0.80774295, 0.8879849, 0.31292745, 0.05584943, 0.8738258]' LIMIT 10;
id  
-----
  82
 130
 145
  69
  80
 200
  22
  31
 182
 (10 rows)

4 - 外部数据包装器 (FDW)

外部数据包装器(FDW)是 PostgreSQL 的一项扩展,允许你像查询本地表一样访问和查询存储在远程数据库中的数据。

外部数据包装器(Foreign Data Wrapper,简称 FDW)是 PostgreSQL 中的一项扩展,允许你像操作本地表一样访问和查询存储在远程数据库中的数据。FDW 提供了一种与不同数据源集成和交互的标准方式。

借助 FDW 扩展,你可以在本地 PostgreSQL 数据库中定义外部表(Foreign Table),用于映射远程数据库中的表结构。这些外部表充当远程数据的代理或包装器,使你能够像操作普通 PostgreSQL 表一样对它们执行 SELECT、INSERT、UPDATE 和 DELETE 操作。

在本教程中,我们将使用内置外部数据包装器的 postgres_fdw 模块。该包装器可用于访问存储在外部 PostgreSQL 服务器中的数据。本文将介绍如何使用 postgres_fdw 访问已安装 pgvecto.rs 扩展的远程 PostgreSQL 集群中的向量索引数据。

部署本地和远程 PostgreSQL 集群

在本教程中,我们将使用 Docker Compose 部署两个 PostgreSQL 集群。

$ echo 'version: "3.7"
services:
  local_db:
    image: tensorchord/pgvecto-rs:pg15-v0.2.0
    ports:
      - "5432:5432"
    environment:
      POSTGRES_PASSWORD: password
    command: >
      -c shared_preload_libraries=vectors.so
    networks:
      localnet:

  foreign_db:
    image: tensorchord/pgvecto-rs:pg15-v0.2.0
    ports:
      - "5433:5432"
    environment:
      POSTGRES_PASSWORD: password
    command: >
      -c shared_preload_libraries=vectors.so
    networks:
      localnet:

networks:
  localnet:
' > docker-compose.yml

$ docker compose up -d
# create extension postgres_fdw in local db
$ psql -h <local_db_ip> -U postgres -p 5432 
DROP EXTENSION IF EXISTS postgres_fdw;
CREATE EXTENSION postgres_fdw;

# create extension vectors in foreign db
$ psql -h <foreign_db_ip> -U postgres -p 5432
DROP EXTENSION IF EXISTS "vectors";
CREATE EXTENSION "vectors";

远程数据库操作

首先,我们需要在远程数据库(foreign_db)中创建一张 test 表并在其上构建向量索引。test 表包含两列:id 和 embedding。其中 embedding 列是类型为 vector(10) 的向量列,id 列是 test 表的主键。

创建表

DROP TABLE IF EXISTS test;
CREATE TABLE test (id integer PRIMARY KEY, embedding vector(10) NOT NULL);
INSERT INTO test SELECT i, ARRAY[random(),random(),random(),random(),random(),random(),random(),random(),random(),random()]::real[] FROM generate_series(1, 100) i;

创建用户

在远程数据库中创建一个名为 fdw_user 的用户,并将 test 表上的 SELECT、INSERT、UPDATE、DELETE 权限授予 fdw_user:

CREATE USER fdw_user WITH ENCRYPTED PASSWORD 'secret';
GRANT SELECT,INSERT,UPDATE,DELETE ON TABLE test TO fdw_user;

创建索引

在 test 表的 embedding 列上创建向量索引。这里使用 flat(暴力搜索)索引类型,并选择 vector_l2_ops(欧氏距离平方)来度量向量距离。其他索引类型和距离函数请参阅索引指南。

CREATE INDEX ON test USING vectors (embedding vector_l2_ops) WITH (options = "[indexing.flat]");

本地数据库操作

在本地数据库中,我们需要创建一张本地表 local 和一个外部服务器 foreign_server。local 表包含两列:id 和 name,其中 id 是主键。foreign_server 用于连接访问远程数据库。

创建本地表

DROP TABLE IF EXISTS local;
CREATE TABLE local (id integer PRIMARY KEY, name VARCHAR(50) NOT NULL);
INSERT INTO local (id, name) VALUES (1, 'terry'), (2, 'jason'), (3, 'curry');

创建本地用户

使用超级用户在本地 PostgreSQL 数据库中执行以下语句,创建一个名为 local_user 的普通用户:

CREATE USER local_user WITH ENCRYPTED PASSWORD 'secret';

创建外部服务器

使用 CREATE SERVER 语句创建外部服务器时,需要指定远程数据库的主机地址、端口和数据库名称:

CREATE SERVER foreign_server
    FOREIGN DATA WRAPPER postgres_fdw
    OPTIONS (host '<foreign_db_ip>', port '5432', dbname 'postgres');

创建用户映射

使用 CREATE USER MAPPING 语句创建本地用户与远程用户之间的映射关系,需提供远程用户的用户名和密码:

CREATE USER MAPPING FOR local_user
    SERVER foreign_server
    OPTIONS (user 'fdw_user', password 'secret');

创建外部表

使用 CREATE FOREIGN TABLE 语句创建远程表的映射表。需要注意,每一列的数据类型必须与远程表的实际类型匹配,并且建议保持列名一致;否则,你需要为每个列单独使用 column_name 参数指定远程表中的列名。

CREATE FOREIGN TABLE foreign_test (id integer, embedding vector(10) NOT NULL)
    SERVER foreign_server
    OPTIONS (schema_name 'public', table_name 'test');

权限授予

为 local_user 授予所需权限:

  • 授予 local_user 使用 postgres_fdw 的权限。
  • 授予 local_user 使用外部服务器 foreign_server 的权限。
  • 授予 local_user 访问 public Schema 下所有表的权限。
GRANT USAGE ON FOREIGN DATA WRAPPER postgres_fdw TO local_user;
GRANT USAGE ON FOREIGN SERVER foreign_server TO local_user;
GRANT SELECT,INSERT,UPDATE,DELETE ON ALL TABLES IN SCHEMA public TO local_user;

查询测试

现在我们可以在本地数据库中通过连接查询(JOIN)访问外部表:

$ psql -h <local_db_ip> -U local_user -p 5432 -d postgres
SELECT l.id, l.name FROM local l LEFT JOIN foreign_test f on l.id = f.id ORDER BY f.embedding <-> '[0.40671515, 0.24202824, 0.37059402, 0.50316447, 0.10779921, 0.80774295, 0.8879849, 0.31292745, 0.05584943, 0.8738258]' LIMIT 10;
 id | name  
----+-------
  2 | jason
  3 | curry
  1 | terry


EXPLAIN SELECT l.id, l.name FROM local l LEFT JOIN foreign_test f on l.id = f.id ORDER BY f.embedding <-> '[0.40671515, 0.24202824, 0.37059402, 0.50316447, 0.10779921, 0.80774295, 0.8879849, 0.31292745, 0.05584943, 0.8738258]' LIMIT 10;
 Limit  (cost=209.63..209.65 rows=10 width=126)
   ->  Sort  (cost=209.63..213.04 rows=1365 width=126)
         Sort Key: ((f.embedding <-> '[0.40671515, 0.24202824, 0.37059402, 0.50316447, 0.10779921, 0.80774295, 0.8879849, 0.31292745, 0.05584943, 0.8738258]'::vector))
         ->  Hash Right Join  (cost=122.15..180.13 rows=1365 width=126)
               Hash Cond: (f.id = l.id)
               ->  Foreign Scan on foreign_test f  (cost=100.00..150.95 rows=1365 width=36)
               ->  Hash  (cost=15.40..15.40 rows=540 width=122)
                     ->  Seq Scan on local l  (cost=0.00..15.40 rows=540 width=122)

5 - Kubernetes

如果你想在运行于 Kubernetes 上的 PostgreSQL 中使用 pgvecto.rs,本教程将演示如何使用 CloudNative-PG 在 Kubernetes 中部署集群。

如果你想在运行于 Kubernetes 上的 PostgreSQL 中使用 pgvecto.rs,可以参考本教程。在本教程中,我们将使用 CloudNative-PG 在 Kubernetes 中部署 PostgreSQL 集群。

环境要求

组件名称 版本要求
helm >= 2.4.1
kubectl >= 1.14
Kubernetes >= 1.24.0

安装 CloudNative-PG

我们使用 CloudNative-PG (cnpg) 在 Kubernetes 中部署 PostgreSQL 集群。你可以通过 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

构建包含 pgvecto.rs 的 PostgreSQL 镜像

我们以官方的 CloudNative-PG Docker 镜像作为基础镜像,并在其中安装 pgvecto.rs。你可以在 Releases 页面查看可用的 pgvecto.rs 版本。

# syntax=docker/dockerfile-upstream:master
ARG CNPG_TAG

FROM ghcr.io/cloudnative-pg/postgresql:$CNPG_TAG

ARG CNPG_TAG
ARG PGVECTORS_TAG
ARG TARGETARCH

# drop to root to install packages
USER root

# install pgvecto.rs
ADD https://github.com/tensorchord/pgvecto.rs/releases/download/$PGVECTORS_TAG/vectors-pg${CNPG_TAG%.*}_${PGVECTORS_TAG#"v"}_$TARGETARCH.deb ./pgvectors.deb
RUN apt install ./pgvectors.deb

USER postgres
$ docker build -t <your-postgresql-image-repo>:15 --build-arg CNPG_TAG=15 --build-arg PGVECTORS_TAG=v0.1.13   --build-arg TARGETARCH=amd64 .

注意:PostgreSQL Docker 镜像的 Tag 必须以 CNPG_TAG(PostgreSQL 主版本号)开头,以便 CloudNative-PG 识别 Postgres 版本。

创建 PostgreSQL 集群

下面提供一个用于在 Kubernetes 中创建 PostgreSQL 集群的示例 YAML 文件,你可以根据实际需求进行修改。请注意以下两点:

  • 配置 shared_preload_libraries 以加载 pgvecto.rs 共享库(也可以在 postInitApplicationSQL 中配置 ALTER SYSTEM SET shared_preload_libraries = "vectors.so"; 来加载共享库)。
  • 执行 CREATE EXTENSION IF NOT EXISTS "vectors"; 以创建 vectors 扩展。
apiVersion: v1
kind: Secret
metadata:
  name: tensorchord
type: kubernetes.io/basic-auth
data:
  password: dGVuc29yY2hvcmQ= # tensorchord 
  username: dGVuc29yY2hvcmQ= # tensorchord
---
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
  name: pgvectors 
spec:
  instances: 1 
  bootstrap:
    initdb:
      database: tensorchord
      postInitApplicationSQL:
        - CREATE EXTENSION IF NOT EXISTS "vectors";
      owner: tensorchord
      secret:
        name: tensorchord
      dataChecksums: true
      encoding: 'UTF8'
  storage:
    size: 1Gi
  imageName: <your-postgresql-image-repo>:<pg-tag>
  postgresql:
    shared_preload_libraries: # load pgvecto.rs shared library
    - "vectors.so"

你可以安装 cnpg 的 kubectl 插件来管理 PostgreSQL 集群。现在我们可以查看集群状态:

$ sudo kubectl get pod
pgvectors-1                                                1/1     Running   0             3m54s

$ kubectl cnpg status pgvectors
Cluster Summary
Name:                pgvectors
Namespace:           default
System ID:           7323107530735296538
PostgreSQL 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:           1
Ready instances:     1
Current 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

注意:本文仅提供最小化配置示例,不包含逻辑复制、流式复制、备份与恢复等高级配置。更多 Cluster 配置项请参阅 CloudNative-PG 官方文档。

连接 PostgreSQL 集群

你可以使用 kubectl port-forward 转发端口并连接到 PostgreSQL 集群:

$ 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

至此,vectors 扩展已安装成功。你可以跳过安装步骤,直接体验快速开始。

6 - 迁移指南

从 pgvector 迁移到 PGVecto.rs 的完整步骤与注意事项。

PGVecto.rs 迁移概览

从 pgvector 迁移

前置条件

从 pgvector 迁移到 PGVecto.rs 时,你通常已经有一张包含 vector 类型列的表。例如:

CREATE TABLE items (id bigserial PRIMARY KEY, embedding vector(3));

并且表中已经插入了一些数据行:

INSERT INTO items (embedding) VALUES ('[1,2,3]'), ('[4,5,6]');

在大多数情况下,表上还会有一个或多个向量索引:

CREATE INDEX ON items USING hnsw (embedding vector_l2_ops);

这是使用 pgvector 时的典型场景。如果满足以下条件,即可开始迁移:

  • 请确认你的 pgvector 扩展并未安装在 vectors Schema 中。这意味着你可以在同一个数据库中同时安装 pgvector 和 PGVecto.rs。

迁移步骤

1. 安装 PGVecto.rs

请按照安装指南安装 PGVecto.rs,并确保 PostgreSQL 已加载该扩展。

CREATE EXTENSION vectors;

此时,pgvector 和 PGVecto.rs 两个扩展已同时安装在 PostgreSQL 中。

要验证安装结果,请在 psql 中运行 \dx。你会看到代表 pgvector 的 vector 扩展,以及代表 PGVecto.rs 的 vectors 扩展。

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

请注意,这两个扩展中存在一些同名的类型和符号,这可能会在迁移过程中引起混淆。为了区分二者,请先确认当前的 search_path 中不包含 PGVecto.rs 的 vectors Schema:

SHOW search_path;
-- 如果显示为:`"$user", public` -> 正常
-- 如果显示为:`"$user", public, vectors` -> 请通过以下命令移除 `vectors`:
SET search_path = "$user, public";

2. 检查现有索引

对于在向量列上创建的索引,请先查询其定义并记录下来,以便在后续阶段重建索引。

postgres=# SELECT indexdef FROM pg_indexes WHERE tablename = 'items';
                                       indexdef                                        
---------------------------------------------------------------------------------------
 CREATE UNIQUE INDEX items_pkey ON public.items USING btree (id)
 CREATE INDEX items_embedding_idx ON public.items USING hnsw (embedding vector_l2_ops)
(2 rows)

3. 迁移向量列

要迁移 pgvector 的向量列,第一步是创建一个对应类型的 PGVecto.rs 向量列,第二步是将原列中的向量数据复制到新列中。

以下是 pgvector 各向量类型的转换路径:

  • vector(pgvector) -> real[] -> vector(PGVecto.rs)
  • halfvec -> vector(pgvector) -> real[] -> vector(PGVecto.rs) -> vecf16
  • bit -> text[] -> real[] -> vector(PGVecto.rs) -> bvector

目前暂不支持迁移以下向量类型:

  • sparsevec

方法一:先验证再替换

使用此方法,你可以在迁移过程中检查向量数据的正确性,而且无需担心原向量列上已创建的索引(在删除原列时索引会自动删除)。 但这种方法需要额外的存储空间来同时保存迁移前后的向量数据。

警告

此步骤会导致一定的停机时间,原因包括:

  • ALTER TABLE ADD COLUMN 会获取短暂的 ACCESS EXCLUSIVE 锁
  • UPDATE 会持有较长时间的 ROW EXCLUSIVE 锁
  • ALTER TABLE DROP COLUMN 会获取短暂的 ACCESS EXCLUSIVE 锁
-- 从 vector 类型转换
ALTER TABLE items ADD COLUMN migrate_embedding vectors.vector(3);
UPDATE items SET migrate_embedding = embedding::real[]::vectors.vector;

-- 从 halfvec 类型转换
ALTER TABLE items ADD COLUMN migrate_embedding vectors.vecf16(3);
UPDATE items SET migrate_embedding = embedding::vector::real[]::vectors.vector::vectors.vecf16;

-- 从 bit 类型转换
ALTER TABLE items ADD COLUMN migrate_embedding vectors.bvector(3);
UPDATE items SET migrate_embedding = string_to_array(embedding::text, NULL)::real[]::vectors.vector::vectors.bvector;

数据复制完成后,你可以通过 SELECT 检查数据,然后用新列替换旧列:

ALTER TABLE items DROP COLUMN embedding;
ALTER TABLE items RENAME COLUMN migrate_embedding TO embedding;

方法二:原地转换(无需额外存储空间)

使用此方法,可以在一条命令内完成列类型转换,无需占用额外的列存储空间。 但你需要提前手动删除该向量列上的索引。

警告

此步骤会导致一定的停机时间,原因包括:

  • ALTER TABLE ALTER COLUMN 会持有较长时间的 ACCESS EXCLUSIVE 锁
-- 索引名称来自第 2 步的查询结果
DROP INDEX IF EXISTS items_embedding_idx;

-- 从 vector 类型转换
ALTER TABLE items ALTER COLUMN embedding TYPE vectors.vector(3) USING embedding::real[]::vectors.vector;

-- 从 halfvec 类型转换
ALTER TABLE items ALTER COLUMN embedding TYPE vectors.vecf16(3) USING embedding::vector::real[]::vectors.vector::vectors.vecf16;

-- 从 bit 类型转换
ALTER TABLE items ALTER COLUMN embedding TYPE vectors.bvector(3) USING string_to_array(embedding::text, NULL)::real[]::vectors.vector::vectors.bvector;

4. 重建索引

要为 PGVecto.rs 的 vector 列重建索引,可以开启兼容模式并直接执行之前的索引创建语句:

SET vectors.pgvector_compatibility=on;
-- 执行第 2 步中记录的命令
CREATE INDEX items_embedding_idx ON public.items USING hnsw (embedding vector_l2_ops);

对于其他向量类型(如 halfvec、sparsevec 和 bit),请参考索引指南重新创建索引。目前 pgvector_compatibility 兼容模式暂不支持这些类型。

5. 清理环境

如果不再需要 pgvector 扩展,现在可以安全地将其卸载:

DROP extension vector;

卸载 pgvector 扩展后,建议重新设置 search_path,以确保可以在全局直接访问 PGVecto.rs 中的符号:

SET search_path = "$user, public, vectors";
-- 或在全局级别设置
ALTER SYSTEM SET search_path = "$user, public, vectors";

验证结果

迁移任务执行完毕后,你可以通过 SELECT 语句验证新列的数据与类型:

SELECT embedding, pg_typeof("embedding") from items limit 3;

-- embedding |   pg_typeof    
-------------+----------------
-- [1, 2, 3] | vectors.vector
-- [4, 5, 6] | vectors.vector