主流向量库接入
本教程共 45 篇 · 第 35 篇 · 更新于 2026-08-16 · 约 9 分钟阅读
本节目标:独立完成三个向量库的接入——PGvector、Redis、Milvus。每个库都能跑通”启动环境→加依赖→写配置→建索引→增删查”全流程,并理解 HNSW 与 IVFFlat 索引的取舍。
35.1 接入的通用套路
不管接哪个向量库,模式都一样:加 starter 依赖、写配置、注入 VectorStore。因为上一章的统一抽象,接入代码几乎相同,差别只在依赖坐标和配置项。
三个库的定位不同,先记住一句话:PGvector 是关系库加扩展,Redis 是内存库加搜索模块,Milvus 是专用向量数据库。
接入顺序建议:先用第 34 章的代码骨架和三个库之一跑通,再横向对比配置差异。三个库的示例代码几乎一致,差别集中在启动环境和配置项上,对照着看印象最深。
35.2 PGvector:PostgreSQL 扩展
PGvector 把向量能力装进 PostgreSQL,业务数据能跟向量放同一张库,事务、备份、权限体系全部复用。对已经在用 PostgreSQL 的团队,它是成本最低的选项。
启动环境
用 Docker 起一个带扩展的实例(命令与镜像见 pgvector 官方文档):
docker run -it --rm --name postgres -p 5432:5432 \
-e POSTGRES_USER=postgres -e POSTGRES_PASSWORD=postgres \
pgvector/pgvector
依赖与配置
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-vector-store-pgvector</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-openai</artifactId>
</dependency>
spring.datasource.url=jdbc:postgresql://localhost:5432/postgres
spring.datasource.username=postgres
spring.datasource.password=postgres
spring.ai.vectorstore.pgvector.index-type=HNSW
spring.ai.vectorstore.pgvector.distance-type=COSINE_DISTANCE
spring.ai.vectorstore.pgvector.dimensions=1536
spring.ai.vectorstore.pgvector.initialize-schema=true
dimensions 必须和嵌入模型一致。不写的话,实现会从 EmbeddingModel 自动取。initialize-schema 默认 false,忘了开,第一次写入就会报表不存在的错误。
distance-type 默认是 COSINE_DISTANCE。如果向量做了归一化(长度恒为 1),可以改用 EUCLIDEAN_DISTANCE 或 NEGATIVE_INNER_PRODUCT,性能更好。没做归一化就保持默认,别乱换。
建表与索引
schema 初始化开启后,表会自动创建。手工建表的 SQL 长这样,理解它对排错很有帮助:
CREATE EXTENSION IF NOT EXISTS vector;
CREATE EXTENSION IF NOT EXISTS hstore;
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
CREATE TABLE IF NOT EXISTS vector_store (
id uuid DEFAULT uuid_generate_v4() PRIMARY KEY,
content text,
metadata json,
embedding vector(1536)
);
CREATE INDEX ON vector_store USING HNSW (embedding vector_cosine_ops);
embedding vector(1536) 是 pgvector 的向量列,括号里的数字必须大于等于模型维度。改维度要重建表,所以先定模型再建表。
HNSW 与 IVFFlat
索引类型是 PGvector 的关键配置,两种算法各有利弊。
HNSW:多层图结构,查询快、召回率高,但建索引慢、占内存。没有训练阶段,空表也能建。PGvector 默认选它,向量维度上限 2000(pgvector 官方文档)。
IVFFlat:把向量分成列表,只搜最近的几个列表。建索引快、省内存,但查询速度和召回率都逊一筹。它需要先有数据训练,空表建索引会告警。
数据量小、追求查询质量选 HNSW;数据量大、资源紧张选 IVFFlat。大多数场景无脑 HNSW 就行。
两个配置提醒。HNSW 的维度上限是 2000,超过这个维度只能用 IVFFlat 或不用索引。IVFFlat 需要先有数据再建索引,它有个训练阶段,空表直接建索引效果会很差。建表时想清楚数据量和维度,再定索引类型。
增删查
注入 VectorStore 直接操作:
@Service
public class PgVectorService {
private final VectorStore vectorStore;
public PgVectorService(VectorStore vectorStore) {
this.vectorStore = vectorStore;
}
public void add(List<Document> documents) {
vectorStore.add(documents);
}
public List<Document> search(String query) {
return vectorStore.similaritySearch(SearchRequest.builder()
.query(query)
.topK(5)
.similarityThreshold(0.7)
.filterExpression("author in ['john', 'jill'] && article_type == 'blog'")
.build());
}
public void delete(String docId) {
vectorStore.delete("docId == '" + docId + "'");
}
}
过滤表达式会被翻译成 PostgreSQL 的 JSON 路径查询,在 metadata 字段上执行。
35.3 Redis:内存向量检索
Redis 本身不是向量库,装上 Redis Stack(带 Search and Query 模块)之后,就能用 HNSW 索引做向量检索。它的优势是快——内存计算,延迟极低,适合高频检索场景。
启动环境
docker run -d --name redis-stack -p 6379:6379 redis/redis-stack:latest
依赖与配置
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-vector-store-redis</artifactId>
</dependency>
spring.data.redis.host=localhost
spring.data.redis.port=6379
spring.ai.vectorstore.redis.initialize-schema=true
spring.ai.vectorstore.redis.index-name=spring-ai-index
spring.ai.vectorstore.redis.prefix=embedding:
spring.ai.vectorstore.redis.distance-metric=COSINE
spring.ai.vectorstore.redis.vector-algorithm=HNSW
index-name 是检索索引名,prefix 是 key 前缀。距离度量支持 COSINE、L2、IP 三种,默认 COSINE。
Redis 有个特别要求:过滤表达式里用到的元数据字段,必须先声明类型。手工配置时用 metadataFields 注册:
@Bean
public VectorStore vectorStore(RedisClient jedisClient, EmbeddingModel embeddingModel) {
return RedisVectorStore.builder(jedisClient, embeddingModel)
.initializeSchema(true)
.metadataFields(
MetadataField.tag("country"), // 标签类型,用于等值/IN 过滤
MetadataField.numeric("year"), // 数值类型,用于范围过滤
MetadataField.text("description")) // 文本类型,用于全文检索
.build();
}
忘了注册的字段,过滤时可能失效,这是 Redis 接入最常见的坑。
增删查
@Service
public class RedisVectorService {
private final VectorStore vectorStore;
public RedisVectorService(VectorStore vectorStore) {
this.vectorStore = vectorStore;
}
public void add(String content, String country, int year) {
Document doc = new Document(content,
Map.of("country", country, "year", year));
vectorStore.add(List.of(doc));
}
public List<Document> search(String query) {
return vectorStore.similaritySearch(SearchRequest.builder()
.query(query)
.topK(5)
.filterExpression("country in ['UK', 'NL'] && year >= 2020")
.build());
}
}
Redis 还支持按半径检索(searchByRange)和全文检索(searchByText),后者是它的独门优势——向量检索和关键词检索可以互补。进阶场景还有语义缓存:把”问题-回答”存进向量索引,新问题先算相似度,命中相似问题就直接返回缓存答案,能省大量模型调用。官方为它单独提供了 SemanticCacheAdvisor,对调用方透明,接入成本很低。
35.4 Milvus:专用向量数据库
Milvus 是为向量检索而生的专用库,支持十亿级数据、丰富的索引类型,适合数据量大、检索要求高的场景。代价是要独立部署一套服务,运维成本比前两个高。
启动环境
Milvus Standalone 用 Docker Compose 起,官方文档有完整编排文件。启动后 gRPC 端口是 19530,管理界面在 9001(minioadmin/minioadmin)。
依赖与配置
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-vector-store-milvus</artifactId>
</dependency>
spring.ai.vectorstore.milvus.client.host=localhost
spring.ai.vectorstore.milvus.client.port=19530
spring.ai.vectorstore.milvus.client.username=root
spring.ai.vectorstore.milvus.client.password=milvus
spring.ai.vectorstore.milvus.database-name=default
spring.ai.vectorstore.milvus.collection-name=vector_store
spring.ai.vectorstore.milvus.embedding-dimension=1536
spring.ai.vectorstore.milvus.index-type=IVF_FLAT
spring.ai.vectorstore.milvus.metric-type=COSINE
spring.ai.vectorstore.milvus.initialize-schema=true
Milvus 的术语不同:库叫 database,表叫 collection(集合)。embedding-dimension 默认 1536,同样要和模型维度对齐。
增删查与 nprobe
常规操作和其他库一样,注入 VectorStore 即可:
vectorStore.add(documents);
List<Document> docs = vectorStore.similaritySearch(
SearchRequest.builder().query("Spring AI").topK(5).build());
Milvus 有个自己的坑:默认索引 IVF_FLAT 检索时靠 nprobe 参数决定搜多少个聚类,默认值只有 1,会导致召回很差甚至搜不到结果。用 MilvusSearchRequest 显式调大:
MilvusSearchRequest request = MilvusSearchRequest.milvusBuilder()
.query("Spring AI")
.topK(5)
.similarityThreshold(0.7)
.searchParamsJson("{\"nprobe\":128}")
.nativeExpression("metadata['category'] == 'science'") // 原生过滤
.build();
List<Document> docs = vectorStore.similaritySearch(request);
nativeExpression 写 Milvus 原生表达式,优先级高于通用 filterExpression。searchParamsJson 里还能传 ef、nprobe 等索引专有参数,是调优的入口。
35.5 三个库怎么选
同一套代码,三个库跑下来只换了依赖和配置。选型先看现状:已有 PostgreSQL 用 PGvector,已有 Redis 且数据量不大用 Redis,数据量百万级以上、检索是核心诉求用 Milvus。更完整的 20 余种实现全景和选型框架在下一章。
还有一点提醒:三个库的 schema 初始化在 2.0 里都是默认关闭的,忘了开 initialize-schema=true,启动不报错,但第一次写入或检索时会失败。配置写完先跑一个增删查冒烟测试,再继续往下做。
Tip起步阶段推荐 PGvector:Docker 一行命令就能跑,SQL 建表逻辑透明,排查问题最直观。跑通 RAG 全流程后再评估要不要换专用库。
35.6 小结
接入向量库是”加依赖、写配置、注入 VectorStore”三件事。PGvector 靠扩展融入 PostgreSQL,索引在 HNSW 和 IVFFlat 之间取舍;Redis 快但要求元数据字段先注册;Milvus 强但多一套运维,还要记得调 nprobe。下一章看全部实现的选型全景。