Docker 快速安装 PostgreSQL + PGvector
我们直接使用官方封装好的镜像,一步到位。打开终端,直接复制并运行下面这段命令(请注意修改 -v 挂载目录为你本地的实际路径):
docker run -d \
--name my_pgvector \
-p 5432:5432 \
-e POSTGRES_PASSWORD=123456 \
-v ./postgresql/data:/var/lib/postgresql/data \
pgvector/pgvector:pg17这条命令会在后台启动一个带有向量扩展(pgvector)的 PostgreSQL 17 数据库容器。
下面对命令进行拆分解释:
docker run -d: -docker run是 Docker 最常用的命令,用于创建一个新的容器并运行一个命令。 --d(detached): 意思是“后台运行”。如果不加这个参数,容器的运行日志会直接占据你的终端窗口,一旦你按下Ctrl+C或者关闭终端,容器通常会停止。加上-d后,容器会在后台静默运行。--name my_pgvector: + 为你的容器指定一个自定义名称叫my_pgvector。方便后续管理。 + 如果没有这个参数,Docker 会随机分配一个像determined_byd这样古怪的名字。有了名字后,你可以直接通过docker stop my_pgvector来停止它。-p 5432:5432: - 端口映射,格式为宿主机端口:容器内端口。 - PostgreSQL 默认在容器内部监听5432端口。通过这个映射,你可以通过访问你电脑(宿主机)的localhost:5432来连接这个数据库。-e POSTGRES_PASSWORD=123456:设置默认超级用户postgres的登录密码。在生产环境下,千万不要用123456这么简单的密码,建议使用复杂的随机字符串。.-v ./postgresql/data:/var/lib/postgresql/data(重要!!!)
- 挂载数据卷(Volume),格式为宿主机绝对路径:容器内路径。
- 这是最关键的部分,用于 数据持久化 。
- 容器是一个“临时”的环境,删除容器会丢失内部所有数据。通过这个映射,数据库产生的所有数据都会实时写入到你的磁盘。即使你删除了容器,下次再挂载这个目录,数据依然存在。pgvector/pgvector:pg17:指定使用的镜像名和标签(Tag)。
PGvector 向量功能
虽然镜像已经内置了向量功能,但 PostgreSQL 的设计是“插件按需加载”。按理说你得手动执行 CREATE EXTENSION vector;。
但是! 如果你用的是 Spring AI,你会发现哪怕不手动输入命令,项目也能跑。这是因为 Spring AI 的 PgVectorStore 已经在底层帮你把脏活累活干了。在 Spring 容器启动时,自动检测并初始化 PostgreSQL 的向量数据库环境。
/**
* PgVectorStore 实现了 InitializingBean 接口。
* Spring 容器在完成 Bean 的属性注入后,会自动调用 afterPropertiesSet() 方法。
*/
public class PgVectorStore extends AbstractObservationVectorStore implements InitializingBean {
@Override
public void afterPropertiesSet() {
// 1. 打印初始化日志,确认当前操作的表名和 Schema 名
logger.info("Initializing PGVectorStore schema for table: {} in schema: {}",
this.getVectorTableName(), this.getSchemaName());
logger.info("vectorTableValidationsEnabled {}", this.schemaValidation);
// 2. 校验逻辑:如果开启了校验,则检查数据库中现有的表结构是否符合要求
if (this.schemaValidation) {
this.schemaValidator.validateTableSchema(this.getSchemaName(), this.getVectorTableName());
}
// 3. 初始化开关:如果 initializeSchema 为 false,则跳过后续的所有建表和安装插件操作
// 这通常用于生产环境,由 DBA 手动预先创建好环境
if (!this.initializeSchema) {
logger.debug("Skipping the schema initialization for the table: {}", this.getFullyQualifiedTableName());
return;
}
// --- 数据库底层环境准备 ---
// 4. 安装 pgvector 插件:这是实现向量检索的核心扩展
this.jdbcTemplate.execute("CREATE EXTENSION IF NOT EXISTS vector");
// 5. 安装 hstore 插件:用于支持键值对存储(通常作为 metadata 的补充)
this.jdbcTemplate.execute("CREATE EXTENSION IF NOT EXISTS hstore");
// 6. 安装 UUID 插件:如果主键类型配置为 UUID,则需要安装此扩展来生成随机 ID
if (this.idType == PgIdType.UUID) {
this.jdbcTemplate.execute("CREATE EXTENSION IF NOT EXISTS \"uuid-ossp\"");
}
// 7. 创建数据库 Schema(命名空间),默认为 "public"
this.jdbcTemplate.execute(String.format("CREATE SCHEMA IF NOT EXISTS %s", this.getSchemaName()));
// --- 表结构处理 ---
// 8. 危险操作:如果配置了 removeExistingVectorStoreTable 为 true,则先删除旧表
// 警告:这会导致数据丢失,通常仅用于集成测试环境
if (this.removeExistingVectorStoreTable) {
this.jdbcTemplate.execute(String.format("DROP TABLE IF EXISTS %s", this.getFullyQualifiedTableName()));
}
// 9. 创建向量存储核心表
// id: 主键,类型根据 getColumnTypeName() 动态决定(如 uuid, serial 等)
// content: 原始文本内容
// metadata: 关联的元数据,存储为 JSON 格式
// embedding: 向量字段,指定维度 vector(N)
this.jdbcTemplate.execute(String.format("""
CREATE TABLE IF NOT EXISTS %s (
id %s PRIMARY KEY,
content text,
metadata json,
embedding vector(%d)
)
""",
this.getFullyQualifiedTableName(),
this.getColumnTypeName(),
this.embeddingDimensions()));
// --- 性能优化:索引 ---
// 10. 创建向量索引:提高相似度搜索的效率
// 如果 createIndexMethod 不是 NONE(如 HNSW 或 IVFFlat),则执行创建索引语句
if (this.createIndexMethod != PgIndexType.NONE) {
this.jdbcTemplate.execute(String.format("""
CREATE INDEX IF NOT EXISTS %s ON %s USING %s (embedding %s)
""",
this.getVectorIndexName(), // 索引名称
this.getFullyQualifiedTableName(), // 表名
this.createIndexMethod, // 索引算法 (如 hnsw)
this.getDistanceType().index // 距离度量函数 (如 vector_cosine_ops)
));
}
}
// ... 其他方法
}不过,需要注意的是:当 initialize-schema: false 时,Spring AI 不会自动创建 vector_store 表(上面源码中我也注释了相应的代码)。
spring:
ai:
vectorstore:
pgvector:
initialize-schema: true 建议开发环境设置为 true,方便快速启动。生产环境设置为 false,手动管理数据库 schema,避免意外变更。