首页 / Spring AI 入门教程 / 主流向量库接入

Spring AI 入门教程

主流向量库接入

本教程共 45 篇 · 第 35 篇 · 更新于 2026-08-16 · 约 9 分钟阅读

Spring AIPGvectorRedisMilvus向量数据库HNSWIVFFlatVectorStore

本节目标:独立完成三个向量库的接入——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_DISTANCENEGATIVE_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 原生表达式,优先级高于通用 filterExpressionsearchParamsJson 里还能传 efnprobe 等索引专有参数,是调优的入口。

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。下一章看全部实现的选型全景。