向量数据库:PostgreSQL + pgvector
在向量数据库:Qdrant中我们介绍了向量数据库的概念以及开源产品 Qdrant。这里我们介绍另一个优秀的开源方案:PostgreSQL + pgvector。
PostgreSQL 是一个稳定可靠、功能强大的开源对象关系型数据库系统,第一个公开版本于 1989 年发布。此后,它经历了多次迭代,并逐渐成为世界上最流行的开源数据库之一。它支持 SQL 标准,并提供复杂查询、事务完整性、多版本并发控制等多种现代数据库技术特性。PostgreSQL 以其高度的扩展性和对大型数据集的强大处理能力而闻名,适用于从小型应用程序到大型企业系统的各种环境。此外,它还拥有一个活跃的开发社区,为开发者提供丰富的资源和工具。
pgvector 是一个用于向量相似性搜索的 PostgreSQL 扩展。安装此扩展后,PostgreSQL 可以支持向量数据的存储、检索和查询等操作。
部署
安装
进入 Notebook app
的终端,添加相应的 Helm Chart repository,列出 Chart bitnami/postgresql
的所有版本:
helm repo add bitnami https://charts.bitnami.com/bitnami
# 注意 CHART VERSION 和 APP VERSION(PostgreSQL 版本)之间的对应关系
# 例如 CHART VERSION 14.1.x 中的 PostgreSQL 版本都是 16.2.0
helm search repo bitnami/postgresql --versions
安装指定版本的 Chart 并指定 t9kpublic/bitnami-pgvector
镜像,以部署包含 pgvector 的 PostgreSQL 应用:
# 安装最新版本
helm repo update bitnami
helm install pgvector-demo bitnami/postgresql \
--set image.repository=t9kpublic/bitnami-pgvector \
--set image.tag=0.6.0-pg16
# 安装指定 CHART VERSION,注意这不是 APP VERSION(PostgreSQL 版本)
helm install pgvector-demo bitnami/postgresql \
--version <CHART_VERSION> \
--set image.repository=t9kpublic/bitnami-pgvector \
--set image.tag=0.6.0-pg16
配置
以上安装全部使用默认配置,完整的默认配置请参阅 Parameters 以及相应的 values.yaml
:
# 获取指定 CHART VERSION 的 values.yaml
helm show values bitnami/postgresql --version <CHART_VERSION> > values.yaml
如果想要修改默认配置,你可以将新配置(覆盖默认配置的字段)保存为一个 YAML 文件,通过 -f
选项提供给安装命令:
# 使用修改后的 values.yaml
helm install pgvector-demo t9kpublic/bitnami-pgvector \
--version <CHART_VERSION> \
--set image.repository=t9kpublic/bitnami-pgvector \
--set image.tag=0.6.0-pg16 \
-f values.yaml
下面将分主题介绍部分关键配置(CHART VERSION 14.1.3)。
计算资源
默认配置没有指定计算资源,表示 Pod 可以无限制地使用节点的 CPU 和内存资源。你可以根据实际需求指定请求值和限制值,可以参阅管理内存用量的最佳实践。
# 默认配置
primary:
resources: {}
存储
默认配置指定的卷大小为 8Gi
,并且没有指定存储类型。你可以根据数据规模修改卷大小,并选用高性能的存储类型。
# 默认配置
primary:
persistence:
existingClaim: "" # 使用已有的 PVC
subPath: "" # 卷被挂载的子路径,用于多个服务共用一个卷
storageClass: "" # 存储类型
accessModes:
- ReadWriteOnce
size: 8Gi # 存储大小
网络
你可以按需修改 Service 配置,提供 tls 配置以提供外部安全访问。
# 默认配置
tls: # tls 配置
enabled: false
autoGenerated: false
preferServerCiphers: true
certificatesSecret: ""
certFilename: ""
certKeyFilename: ""
certCAFilename: ""
crlFilename: ""
primary:
service: # Service 配置
type: ClusterIP
ports:
postgresql: 5432
clusterIP: ""
loadBalancerIP: ""
externalTrafficPolicy: Cluster
安全
你可以设置 postgres
管理员用户的密码,
请参阅 Setting the root password on first run。
auth:
enablePostgresUser: true # 启用 postgres 管理员用户
postgresPassword: "" # postgres 管理员用户的密码
备份
你可以启用数据库的定时备份并提供相应配置。注意这里的备份方法是转储(dump)而不是快照(snapshot)。
# 默认配置
backup:
enabled: false
cronjob:
schedule: "@daily"
timeZone: ""
podSecurityContext:
enabled: true
fsGroupChangePolicy: Always
sysctls: []
supplementalGroups: []
fsGroup: 1001
containerSecurityContext:
enabled: true
seLinuxOptions: null
runAsUser: 1001
runAsNonRoot: true
privileged: false
readOnlyRootFilesystem: false
allowPrivilegeEscalation: false
capabilities:
drop: ["ALL"]
seccompProfile:
type: "RuntimeDefault"
command:
- /bin/sh
- -c
- "pg_dumpall --clean --if-exists --load-via-partition-root --quote-all-identifiers --no-password --file=${PGDUMP_DIR}/pg_dumpall-$(date '+%Y-%m-%d-%H-%M').pgdump"
storage:
existingClaim: ""
storageClass: ""
accessModes:
- ReadWriteOnce
size: 8Gi
subPath: ""
应用架构
应用的系统架构如下图所示(CHART VERSION 14.1.3,默认配置):
创建的主要 Kubernetes 资源如下表所示:
类型 | 名称 | 作用 | 备注 |
---|---|---|---|
Service | pgvector-demo-postgresql | 暴露 PostgreSQL 服务 | |
StatefulSet | pgvector-demo-postgresql | 部署 PostgreSQL + pgvector(包括持久化存储) | 默认计算资源为 {} |
PVC | data-pgvector-demo-postgresql-* | 作为 PostgreSQL 的持久化存储 | 默认卷大小为 8Gi |
Secret | pgvector-demo-postgresql | 存储 postgres 密钥 |
运维
查看应用的状态
helm status pgvector-demo
更新应用,下面的 image.tag
可能需要设置为其他值。
# 更新到最新版本
helm upgrade pgvector-demo t9kpublic/bitnami-pgvector \
--set image.repository=t9kpublic/bitnami-pgvector \
--set image.tag=0.6.0-pg16
# 更新到指定版本
helm upgrade pgvector-demo t9kpublic/bitnami-pgvector \
--version <CHART_VERSION> \
--set image.repository=t9kpublic/bitnami-pgvector \
--set image.tag=0.6.0-pg16
# 回滚更新,首先查看历史版本
helm history pgvector-demo
helm rollback pgvector-demo [REVISION]
移除应用
helm delete pgvector-demo
kubectl delete pvc -l app.kubernetes.io/instance=pgvector-demo
使用
继续使用 Notebook app
的终端,获取应用的密钥,并连接到 PostgreSQL 实例:
export POSTGRES_PASSWORD=$(kubectl get secret --namespace demo pgvector-demo-postgresql -o jsonpath="{.data.postgres-password}" | base64 -d)
kubectl run pgvector-demo-postgresql-client \
--rm --tty -i --restart='Never' --namespace demo \
--image docker.io/t9kpublic/bitnami-pgvector:main \
--env="PGPASSWORD=$POSTGRES_PASSWORD" \
--command -- \
psql --host pgvector-demo-postgresql -U postgres -d postgres -p 5432
使用 psql 命令启用 pgvector 扩展:
CREATE EXTENSION vector;
然后运行一个快速入门:
CREATE TABLE items (id bigserial PRIMARY KEY, embedding vector(3));
INSERT INTO items (embedding) VALUES ('[1,2,3]'), ('[4,5,6]');
SELECT * FROM items ORDER BY embedding <-> '[3,1,2]' LIMIT 5;
DROP TABLE items;
接下来运行一个 Python 语言的官方示例。先安装必要的 Python 库:
pip install pgvector "psycopg[binary]" sentence_transformers
然后执行如下 Python 脚本,命令行参数需要提供连接字符串:
sentence_embeddings.py
import sys
from pgvector.psycopg import register_vector
import psycopg
from sentence_transformers import SentenceTransformer
# 创建数据库连接,并设置自动提交
conn = psycopg.connect(sys.argv[1], autocommit=True)
# 启用 pgvector 扩展,注册向量数据类型
conn.execute('CREATE EXTENSION IF NOT EXISTS vector')
register_vector(conn)
# 重新创建表 documents
conn.execute('DROP TABLE IF EXISTS documents')
conn.execute('CREATE TABLE documents (id bigserial PRIMARY KEY, content text, embedding vector(384))')
# 嵌入输入文本
input = [
'The dog is barking',
'The cat is purring',
'The bear is growling'
]
model = SentenceTransformer('all-MiniLM-L6-v2')
embeddings = model.encode(input)
# 将输入文本和相应的嵌入向量插入到数据库中
for content, embedding in zip(input, embeddings):
conn.execute('INSERT INTO documents (content, embedding) VALUES (%s, %s)', (content, embedding))
# 查询与指定文档最相近的其他文档的文本内容
document_id = 1
neighbors = conn.execute('SELECT content FROM documents WHERE id != %(id)s ORDER BY embedding <=> (SELECT embedding FROM documents WHERE id = %(id)s) LIMIT 5', {'id': document_id}).fetchall()
for neighbor in neighbors:
print(neighbor[0])
export POSTGRES_PASSWORD=$(kubectl get secret --namespace demo pgvector-demo-postgresql -o jsonpath="{.data.postgres-password}" | base64 -d)
python pgvector-test.py "host=pgvector-demo-postgresql port=5432 dbname=postgres user=postgres password=$POSTGRES_PASSWORD"
脚本创建了一个表,添加了一些向量数据,并进行了一次基本的向量查询。输出应类似于:
The bear is growling
The cat is purring
更多信息请参阅 pgvector 的 README 文档。