pgvector 是 PostgreSQL 的扩展插件 ,编译它需要 PostgreSQL 的开发环境(pg_config 工具),但 AutoDL 容器默认没有安装 PostgreSQL。
一、在 AutoDL 容器内安装 PostgreSQL + pgvector
# 1. 更新包列表并安装 PostgreSQL 及开发包
sudo apt-get update
sudo apt-get install -y postgresql postgresql-contrib postgresql-server-dev-all
# 2. 启动 PostgreSQL 服务
service postgresql start
# 3. 切换到 postgres 用户
su - postgres
# 4. 进入 pgvector 目录编译安装
cd /root/autodl-tmp/pgvector
make
sudo make install
# 5. 启用扩展
psql -c "CREATE EXTENSION IF NOT EXISTS vector;"
注意:AutoDL 容器重启后数据会丢失。
AutoDL 特别注意
- 容器重启数据会丢失 → 重要数据存
/root/autodl-pub- PostgreSQL 服务不会自动启动 → 每次重启容器需手动
service postgresql start- 端口限制 → AutoDL 默认只开放特定端口,数据库建议用本地连接或配置自定义端口
postgres用户没有权限访问/root/autodl-tmp/pgvector目录,因为这是root用户创建的目录。
# 退出 postgres 用户,回到 root
exit
# 在 root 用户下执行编译安装
cd /root/autodl-tmp/pgvector
make
make install
# 然后切换到 postgres 用户启用扩展
su - postgres
psql -c "CREATE EXTENSION IF NOT EXISTS vector;"
make install会把编译好的文件安装到系统目录(如/usr/share/postgresql/),postgres 用户可以直接使用。
pgvector 安装验证完整步骤
1. 检查 PostgreSQL 服务状态
# 查看服务状态
service postgresql status
# 或
pg_isready
2. 检查 pgvector 扩展是否安装成功
# 切换到 postgres 用户
su - postgres
# 查看已安装的扩展
psql -c "\dx" | grep vector
输出:
vector | 0.8.1 | public | vector data type and ivfflat and hnsw access methods
3. 检查 vector 数据类型是否可用
# 查看 vector 类型
psql -c "\dT" | grep vector
输出:
public | vector |
4. 创建测试数据库并验证向量功能
# 创建测试数据库
psql -c "CREATE DATABASE vector_test;"
# 连接测试数据库
psql -d vector_test
# 在 psql 交互界面中执行以下命令:
-- 1. 启用扩展
CREATE EXTENSION IF NOT EXISTS vector;
-- 2. 创建测试表(带向量列)
CREATE TABLE test_vectors (
id SERIAL PRIMARY KEY,
name TEXT,
embedding vector(3) -- 3维向量
);
-- 3. 插入测试数据
INSERT INTO test_vectors (name, embedding) VALUES
('向量1', '[1, 2, 3]'),
('向量2', '[4, 5, 6]'),
('向量3', '[7, 8, 9]');
-- 4. 查询数据
SELECT * FROM test_vectors;
-- 5. 测试向量相似度搜索(余弦相似度)
SELECT name, embedding,
embedding <-> '[1, 2, 3]' AS distance
FROM test_vectors
ORDER BY distance
LIMIT 2;
-- 6. 退出 psql
\q
5.创建测试数据库并验证
# 创建数据库
createdb vector_test
# 连接数据库并启用扩展
psql -d vector_test -c "CREATE EXTENSION IF NOT EXISTS vector;"
# 检查扩展是否成功
psql -d vector_test -c "\dx" | grep vector
# 检查 vector 类型
psql -d vector_test -c "\dT" | grep vector
6.直接执行以下命令测试向量功能:
psql -d vector_test << 'SQL'
-- 1. 创建测试表
CREATE TABLE test_vectors (
id SERIAL PRIMARY KEY,
name TEXT,
embedding vector(3)
);
-- 2. 插入测试数据
INSERT INTO test_vectors (name, embedding) VALUES
('向量1', '[1, 2, 3]'),
('向量2', '[4, 5, 6]'),
('向量3', '[7, 8, 9]');
-- 3. 查询所有数据
SELECT * FROM test_vectors;
-- 4. 测试向量相似度搜索(余弦距离)
SELECT name, embedding <-> '[1, 2, 3]' AS distance
FROM test_vectors
ORDER BY distance
LIMIT 2;
-- 5. 测试内积相似度
SELECT name, embedding <#> '[1, 2, 3]' AS inner_product
FROM test_vectors
ORDER BY inner_product DESC
LIMIT 2;
-- 6. 测试余弦相似度
SELECT name, embedding <=> '[1, 2, 3]' AS cosine_similarity
FROM test_vectors
ORDER BY cosine_similarity DESC
LIMIT 2;
SQL
echo "pgvector 全部验证完成!"
输出:
id | name | embedding
----+-------+-----------
1 | 向量1 | [1,2,3]
2 | 向量2 | [4,5,6]
3 | 向量3 | [7,8,9]
(3 rows)
name | distance
-------+-------------------
向量1 | 0
向量2 | 5.196152422706632
(2 rows)
name | inner_product
-------+---------------
向量1 | -14
向量2 | -32
(2 rows)
name | cosine_similarity
-------+----------------------
向量3 | 0.04058805443332969
向量2 | 0.025368153802923787
(2 rows)
常用向量操作速查表
| 运算符 | 说明 | 用途 |
|---|---|---|
<-> |
欧几里得距离 | 越小越相似 |
<#> |
负内积 | 越大越相似 |
<=> |
余弦距离 | 越小越相似(0=完全相同) |
<+> |
L1 距离 | 曼哈顿距离 |
二、创建向量索引(提升查询速度)
psql -d vector_test << 'SQL'
-- IVFFlat 索引(适合大数据量)
CREATE INDEX ON test_vectors USING ivfflat (embedding vector_cosine_ops) WITH (lists = 100);
-- 或 HNSW 索引(更准确但占用更多内存)
-- CREATE INDEX ON test_vectors USING hnsw (embedding vector_cosine_ops);
SQL
先说问题:为什么需要索引?
想象有一个 图书馆 ,里面有 100 万本书(向量数据)。
没有索引时:
有人问:"找一本和《哈利波特》最相似的书"
图书管理员只能 一本一本对比,看完100万本才能告诉你答案 😫
耗时:几小时甚至几天
有索引时:
图书管理员先看 分类目录,直接锁定"魔法类→奇幻小说→英国作家"区域
只需要对比 几百本 就能找到最相似的
耗时:几秒钟
两种索引方式对比
IVFFlat 索引 ------ "分区查找法"
把100万个向量分成 100 个"簇"(类似100个书架)
┌─────────────────────────────────┐
│ 整个向量空间 │
│ ┌───┐ ┌───┐ ┌───┐ ┌───┐ │
│ │簇1│ │簇2│ │簇3│ │簇4│ ... │
│ └───┘ ───┘ ───┘ ───┘ │
└─────────────────────────────────┘
查询时:
1. 先确定你的查询向量属于哪个"簇"
2. 只在这个簇里找最相似的
3. 忽略其他99个簇
| 特点 | 说明 |
|---|---|
| 速度 | 快(比不索引快10-100倍) |
| 准确度 | 可能漏掉一些相似向量(近似搜索) |
| 内存占用 | 小 |
| 适用场景 | 数据量大(>10万条),追求速度 |
| 参数 lists | 分多少个簇,一般设为 数据量/1000 |
生活类比:
就像找对象,先看"年龄段→城市→职业"筛选,再在这个小圈子里找最合适的,而不是全网海选。
HNSW 索引 ------ "朋友圈推荐法"
建立一个多层"社交网络"
第3层(顶层): A────B────C
│ │ │
第2层(中层): D─E─F─G─H─I
│ │ │ │ │ │
第1层(底层): J-K-L-M-N-O-P...(所有数据)
查询时:
1. 从顶层开始,找最近的"朋友"
2. 逐层向下,范围越来越精确
3. 最后在底层找到最相似的几个
| 特点 | 说明 |
|---|---|
| 速度 | 更快(比IVFFlat还快) |
| 准确度 | 更高(更接近精确搜索) |
| 内存占用 | 大(需要建图结构) |
| 适用场景 | 对准确度要求高,内存充足 |
| 构建时间 | ⏱️ 较慢(建索引花时间) |
生活类比:
就像通过朋友介绍朋友,层层推荐,最后找到最匹配的人。比大海捞针快,比分区查找准。
两种索引怎么选?
┌────────────────────────────────────────────────────────────┐
│ 选择指南 │
├────────────────────────────────────────────────────────────┤
│ 数据量 < 1万条 → 不用索引,直接暴力搜索就行 │
│ 数据量 1万-10万 → IVFFlat 足够 │
│ 数据量 > 10万 → HNSW 更优(如果内存够) │
│ 要求100%准确 → 不用索引,或 HNSW + 高参数 │
│ 内存有限 → IVFFlat │
│ 追求极致速度 → HNSW │
└────────────────────────────────────────────────────────────┘
实际创建命令(带注释)
-- ========== IVFFlat 索引 ==========
-- 假设你有 10万条数据,lists 设为 100(10万/1000)
CREATE INDEX ON 你的表名
USING ivfflat (embedding vector_cosine_ops)
WITH (lists = 100);
-- 查询时需要设置搜索的簇数量(默认40)
SET ivfflat.probes = 50; -- 越大越准,但越慢
-- ========== HNSW 索引 ==========
CREATE INDEX ON 你的表名
USING hnsw (embedding vector_cosine_ops)
WITH (m = 16, ef_construction = 64);
-- m: 每个节点的"朋友"数量,越大越准但占用越多
-- ef_construction: 建索引时的搜索深度,越大建得越好但越慢
-- 查询时设置搜索深度
SET hnsw.ef_search = 40; -- 越大越准,但越慢
一句话总结
| 索引类型 | 一句话解释 |
|---|---|
| IVFFlat | "先分区域,再在区域内找" ------ 快,省内存,可能漏 |
| HNSW | "朋友介绍朋友" ------ 更快,更准,吃内存 |
| 不索引 | "一本一本翻" ------ 慢,但100%准确 |
性能对比示例(100万条向量)
| 方式 | 查询时间 | 准确率 | 内存占用 |
|---|---|---|---|
| 不索引 | 5000ms | 100% | 低 |
| IVFFlat | 50ms | 95% | 中 |
| HNSW | 20ms | 98% | 高 |
建议
根据你的 pgvector 0.8.1 版本,两个索引都支持。建议:
-- 如果数据量 < 5万条
CREATE INDEX ON test_vectors USING ivfflat (embedding vector_cosine_ops) WITH (lists = 50);
-- 如果数据量 > 5万条 且 内存充足
CREATE INDEX ON test_vectors USING hnsw (embedding vector_cosine_ops);
三、AutoDL 上 Docker 打包 pgvector 完整流程
pgvector 已经在 AutoDL 上配置好了,用 Docker 打包是最方便的离线部署方式!
整体流程
┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ──────────────┐
│ AutoDL 容器 │ → │ 创建镜像 │ → │ 保存为tar │ → │ 下载到本地 │
└──────────────┘ └──────────────┘ ──────────────┘ └──────────────┘
↓
┌──────────────┐ ┌──────────────┐ ──────────────┐ ┌──────────────┐
│ 离线服务器 │ ← │ 加载镜像 │ ← │ 上传tar │ ← │ 本地存储 │
└──────────────┘ └──────────────┘ └──────────────┘ └──────────────┘
步骤 1:在 AutoDL 上创建 Docker 镜像
1.1 先确认 Docker 可用
# 检查 Docker 是否安装
docker --version
# 如果没有,安装 Docker
curl -fsSL https://get.docker.com | bash
1.2 创建 Dockerfile
cd /root/autodl-tmp
# 创建 Dockerfile
cat > Dockerfile << 'EOF'
FROM pgvector/pgvector:pg16
# 设置环境变量
ENV POSTGRES_PASSWORD=your_password
ENV POSTGRES_DB=vector_test
# 复制 pgvector 扩展文件(如果自定义编译过)
# COPY --chown=postgres:postgres /usr/share/postgresql/14/extension/vector* /usr/share/postgresql/14/extension/
# COPY --chown=postgres:postgres /usr/lib/postgresql/14/lib/vector.so /usr/lib/postgresql/14/lib/
# 复制初始化 SQL 脚本
COPY init.sql /docker-entrypoint-initdb.d/
# 暴露端口
EXPOSE 5432
EOF
# 创建初始化 SQL 脚本
cat > init.sql << 'EOF'
-- 创建扩展
CREATE EXTENSION IF NOT EXISTS vector;
-- 创建测试表
CREATE TABLE IF NOT EXISTS test_vectors (
id SERIAL PRIMARY KEY,
name TEXT,
embedding vector(3)
);
-- 插入测试数据
INSERT INTO test_vectors (name, embedding) VALUES
('向量1', '[1, 2, 3]'),
('向量2', '[4, 5, 6]'),
('向量3', '[7, 8, 9]');
EOF
1.3 构建 Docker 镜像
# 构建镜像
docker build -t pgvector-offline:1.0 .
# 验证镜像
docker images | grep pgvector
步骤 2:保存镜像为 tar 文件
# 保存镜像
docker save -o /root/autodl-pub/pgvector-offline.tar pgvector-offline:1.0
# 查看文件大小
ls -lh /root/autodl-pub/pgvector-offline.tar
# 压缩(可选,减小体积)
gzip /root/autodl-pub/pgvector-offline.tar
# 生成 pgvector-offline.tar.gz
步骤 3:在离线服务器上加载镜像
# 解压(如果压缩了)
gunzip pgvector-offline.tar.gz
# 加载镜像
docker load -i pgvector-offline.tar
# 验证镜像
docker images | grep pgvector
# 运行容器
docker run -d \
--name postgres-vector \
-e POSTGRES_PASSWORD=你的强密码 \
-e POSTGRES_DB=vector_test \
-p 5432:5432 \
-v /data/postgres_data:/var/lib/postgresql/data \
--restart always \
pgvector-offline:1.0
# 验证连接
docker exec -it postgres-vector psql -U postgres -d vector_test -c "\dt"
步骤 4:验证离线环境
# 进入容器
docker exec -it postgres-vector psql -U postgres -d vector_test
# 执行测试查询
SELECT * FROM test_vectors;
-- 测试向量搜索
SELECT name, embedding <-> '[1, 2, 3]' AS distance
FROM test_vectors
ORDER BY distance
LIMIT 2;
-- 退出
\q
完整一键脚本(AutoDL 上执行)
创建 package_pgvector.sh:
#!/bin/bash
echo "开始打包 pgvector Docker 镜像..."
cd /root/autodl-tmp
# 1. 创建 Dockerfile
cat > Dockerfile << 'EOF'
FROM pgvector/pgvector:pg16
ENV POSTGRES_PASSWORD=auto_password
ENV POSTGRES_DB=vector_test
COPY init.sql /docker-entrypoint-initdb.d/
EXPOSE 5432
EOF
# 2. 创建初始化 SQL
cat > init.sql << 'EOF'
CREATE EXTENSION IF NOT EXISTS vector;
CREATE TABLE IF NOT EXISTS test_vectors (
id SERIAL PRIMARY KEY,
name TEXT,
embedding vector(3)
);
INSERT INTO test_vectors (name, embedding) VALUES
('向量1', '[1, 2, 3]'),
('向量2', '[4, 5, 6]'),
('向量3', '[7, 8, 9]');
EOF
# 3. 构建镜像
docker build -t pgvector-offline:1.0 .
# 4. 保存镜像
docker save -o /root/autodl-pub/pgvector-offline.tar pgvector-offline:1.0
# 5. 压缩
gzip /root/autodl-pub/pgvector-offline.tar
# 6. 显示结果
echo "打包完成!"
echo "文件位置:/root/autodl-pub/pgvector-offline.tar.gz"
ls -lh /root/autodl-pub/pgvector-offline.tar.gz
执行脚本:
chmod +x package_pgvector.sh
./package_pgvector.sh
离线服务器部署脚本
创建 deploy_pgvector.sh:
#!/bin/bash
echo "开始部署 pgvector 离线环境..."
# 1. 加载镜像
docker load -i pgvector-offline.tar.gz
# 2. 创建数据目录
mkdir -p /data/postgres_data
chown -R 999:999 /data/postgres_data
# 3. 运行容器
docker run -d \
--name postgres-vector \
-e POSTGRES_PASSWORD=你的强密码 \
-e POSTGRES_DB=vector_test \
-p 5432:5432 \
-v /data/postgres_data:/var/lib/postgresql/data \
--restart always \
pgvector-offline:1.0
# 4. 等待启动
sleep 5
# 5. 验证
docker exec -it postgres-vector psql -U postgres -d vector_test -c "SELECT version();"
echo " 部署完成!"
echo " 连接信息:"
echo " 主机:localhost"
echo " 端口:5432"
echo " 数据库:vector_test"
echo " 用户名:postgres"
echo " 密码:你的强密码"