本章代码已分享至Gitee:https://gitee.com/lengcz/ai-study.git
文章目录
- 向量数据库
- [Spring AI 支持的向量数据库有哪些](#Spring AI 支持的向量数据库有哪些)
- [Spring AI 中如何使用向量数据呢(以redis stack为例)](#Spring AI 中如何使用向量数据呢(以redis stack为例))
- 配置SimpleVectorStore(简单的内存向量模型)
- 文档处理和向量写入
-
- 读取完成文档拆分
-
- 这个Document有什么组成?
- [PDF Reader(示例)](#PDF Reader(示例))
- 向量搜索
向量数据库
向量数据库的核心作用是实现语义层面的相似性检索,区别于传统数据库的字面精确匹配,能快速找到"含义最贴近"的数据,是AI时代的关键基础设施。
核心基础能力
它可将文本、图片、音视频等非结构化数据转化为高维向量,通过余弦相似度、欧氏距离计算向量间的接近程度,完成高效的相似性匹配检索,支持亿级规模向量的毫秒级查询。
主流落地场景
支撑RAG检索增强生成,为大模型对接外部知识库,大幅缓解大模型"幻觉"问题,提升回答的准确性和时效性。
应用于推荐系统,基于用户兴趣向量实现精准的内容、商品匹配推送。
落地以图搜图、语音/视频内容检索、异常检测等场景,完成多模态数据的快速相似查找。
Spring AI 支持的向量数据库有哪些
官网文档地址: https://docs.spring.io/spring-ai/reference/1.0/api/vectordbs.html
VectorStore 的实现,Spring AI支持以下向量数据库
| 数据库名称 | 官方描述 | 数据库类型 | 适用场景 / 特点 |
|---|---|---|---|
| Azure Vector Search | The Azure vector store. | 云服务(全托管) | 深度集成Azure生态,适合微软云用户 |
| Apache Cassandra | The Apache Cassandra vector store. | NoSQL(宽列) | 高可用、大规模分布式写入,适合海量数据 |
| Chroma | The Chroma vector store. | 专用向量数据库 | 轻量级、开源,适合本地开发和原型验证 |
| Elasticsearch | The Elasticsearch vector store. | 搜索引擎 | 已有ES集群,需同时支持全文检索+向量检索 |
| GemFire | The GemFire vector store. | 企业级内存数据库 | VMware生态,高性能缓存与实时计算场景 |
| MariaDB | The MariaDB vector store. | 关系型 (SQL) | 基于MySQL分支,适合小型到中型数据量 |
| Milvus | The Milvus vector store. | 专用向量数据库 | 高性能、分布式,适合大规模生产环境 |
| MongoDB Atlas | The MongoDB Atlas vector store. | NoSQL(文档) | JSON文档存储与向量检索结合,灵活易用 |
| Neo4j | The Neo4j vector store. | NoSQL(图数据库) | 需同时处理知识图谱/关系网络与向量检索 |
| OpenSearch | The OpenSearch vector store. | 搜索引擎 | AWS开源版ES,适合云上与全文检索融合 |
| Oracle | The Oracle Database vector store. | 关系型 (SQL) | 企业级重型数据库,适合已有Oracle栈的客户 |
| PgVector | The PostgreSQL/PGVector vector store. | 关系型 (SQL) | Postgres扩展,最适合已用PG的技术栈 |
| Pinecone | The PineCone vector store. | 专用向量数据库(云原生) | 全托管、低延迟,适合SaaS和Serverless应用 |
| Qdrant | The Qdrant vector store. | 专用向量数据库 | 高性能、Rust编写,支持过滤和Payload丰富 |
| Redis | The Redis vector store. | NoSQL(键值/缓存) | 实时性要求极高,需结合缓存与向量检索 |
| SAP Hana | The SAP HANA vector store. | 企业级内存列式数据库 | 已有SAP生态,需进行实时分析和向量融合 |
| Typesense | The Typesense vector store. | 搜索引擎 | 轻量、易用,追求开箱即用的搜索体验 |
| Weaviate | The Weaviate vector store. | 专用向量数据库 | 内置GraphQL,支持混合搜索和自动向量化 |
| SimpleVectorStore | A simple implementation... good only for testing. | 内存级测试实现 | 仅限开发/单元测试,不适用于生产 |

Spring AI 中如何使用向量数据呢(以redis stack为例)
注意:这里的redis 不是指redis缓存服务器,是指redis stack。
官网文档地址: https://docs.spring.io/spring-ai/reference/1.0/api/vectordbs/redis.html
安装redis stack
这里为了方便,提供docker命令安装
bash
docker run -d --name redis-stack -p 6379:6379 -p 8001:8001 redis/redis-stack:latest

引入依赖

xml
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-vector-store-redis</artifactId>
</dependency>
配置文件
yaml
spring:
data:
redis:
url: 127.0.0.1:6379
ai:
vectorstore:
redis:
initialize-schema: true #向量库索引名
index-name: my_doc_ai_index #是否初始化向量向量索引结构
prefix: "doc:" #向量库key浅醉

如何使用
Spring AI已经为所有向量数据库统一了一套接口,都实现了VectorStore,各向量数据库除了依赖和配置有差异外,使用方式都相同。
以下是 VectorStore接口的定义
java
/**
* 向量存储接口,用于管理文档的向量化表示及其持久化。
* 提供添加、删除以及基于向量相似度的检索能力。
* 继承自 {@link DocumentWriter},支持文档写入操作。
*/
public interface VectorStore extends DocumentWriter {
/**
* 获取当前向量存储实例的名称。
* 默认实现返回类的简单名称(不含包路径)。
*
* @return 存储实例的名称,默认使用类名
*/
default String getName() {
return this.getClass().getSimpleName();
}
/**
* 批量添加文档到向量存储中。
* 实现类需将文档内容转换为向量表示并存储,同时保存元数据以便后续检索。
*
* @param documents 要添加的文档列表,不能为空
*/
void add(List<Document> documents);
/**
* 根据文档 ID 列表批量删除文档。
*
* @param idList 要删除的文档 ID 列表
*/
void delete(List<String> idList);
/**
* 根据过滤表达式删除符合条件的文档。
* 使用结构化过滤表达式(如字段比较、逻辑组合)进行条件删除。
*
* @param filterExpression 过滤表达式,定义删除条件
*/
void delete(Filter.Expression filterExpression);
/**
* 根据字符串形式的过滤表达式删除文档(默认实现)。
* 提供一种便捷的字符串表达式解析方式,具体语法由子类实现。
* 默认实现抛出 {@link UnsupportedOperationException},建议子类覆写。
*
* @param filterExpression 字符串形式的过滤表达式
*/
default void delete(String filterExpression) {
// 默认实现为空或抛出异常,这里以省略号表示原有逻辑
throw new UnsupportedOperationException("String filter expression not supported by default.");
}
/**
* 执行基于向量相似度的搜索,使用默认的查询向量(由 query 字符串生成)。
* 返回与查询最相似的文档列表,通常按相似度降序排列。
*
* @param query 查询文本,将自动转换为向量
* @return 与查询相似的文档列表
*/
List<Document> similaritySearch(String query);
/**
* 执行基于向量相似度的搜索,支持丰富的搜索参数。
* 可以通过 {@link SearchRequest} 指定查询向量、返回数量、过滤条件、相似度阈值等。
*
* @param request 搜索请求对象,封装所有检索参数
* @return 符合搜索条件的文档列表
*/
List<Document> similaritySearch(SearchRequest request);
/**
* 获取底层原生客户端的可选实例。
* 当向量存储基于某个第三方库(如 Elasticsearch、Pinecone 等)实现时,
* 可通过此方法暴露原始客户端,以便进行高级操作。
* 默认返回 {@link Optional#empty()},表示不支持或无需暴露。
*
* @param <T> 原生客户端类型
* @return 包含原生客户端的 Optional,若不存在则为空
*/
default <T> Optional<T> getNativeClient() {
return Optional.empty();
}
}
配置SimpleVectorStore(简单的内存向量模型)
SimpleVectorStore 仅用于学习,请勿用于生产和测试
引入依赖
xml
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-vector-store</artifactId>
<version>${spring-ai.version}</version> <!-- 请使用实际的 Spring AI 版本 -->
</dependency>
配置SimpleVectorStore
java
@Bean
public VectorStore vectorStore(OpenAiEmbeddingModel model){
return SimpleVectorStore.builder(model).build();
}
文档处理和向量写入
读取完成文档拆分

这里文档需要经过读取,转换,写入 三个操作,实现文档写入到向量数据库。
这个Document有什么组成?

Document的组成
- id: 文档的id
- content: 内容
- metadata: 元数据,文件名,文件大小,创建时间,修改时间等
- Media: 媒体,就是音频,视频等文件
而针对Document Reader 文档读取过程,spring-ai已经提供了很多相关的Reader支持不同文件类型的读取解析。
- JSON
- Text
- Markdown
- PDF Page
- PDF Paragraph
- Tika(DOCX,PPT,HTML...)
PDF Reader(示例)
其他Document Reader 请参考官网文档:https://docs.spring.io/spring-ai/reference/1.0/api/etl-pipeline.html#page-title
spring ai 提供了针对不同文件类型的Document Reader,根据不同文档类型,引入不同的依赖
PDF 这里引入的依赖
xml
<!--Document Reader 针对Pdf 的reader-->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-pdf-document-reader</artifactId>
</dependency>
读取并写入到向量数据库
java
@Test
void writeFileToVectorStore(){
// 1. 准备 PDF 资源(从 classpath 加载)
Resource pdfResource = new ClassPathResource("40、狂神说Docker.pdf");
// 2. 配置 PDF 读取器(可选)
PdfDocumentReaderConfig config = PdfDocumentReaderConfig.builder()
.withPageExtractedTextFormatter(ExtractedTextFormatter.defaults()) // 每页最大词数
.withPagesPerDocument(1) //每1页作为一个Document
.build();
// 3. 创建 PagePdfDocumentReader 实例
PagePdfDocumentReader pdfReader = new PagePdfDocumentReader(pdfResource, config);
// 4. 读取 PDF 文档,返回 Document 列表
List<org.springframework.ai.document.Document> documents = pdfReader.get();
// 或使用 pdfReader.read()
// 5. 验证读取结果
System.out.println("读取到 " + documents.size() + " 页文档");
// 7. 写入向量数据库
vectorStore.add(documents);
// 8. 验证写入结果
System.out.println("成功写入 " + documents.size() + " 个文档块到向量数据库");
List<Document> result = vectorStore.similaritySearch("谁创办了Docker");
if(null==result){
System.out.println("没有找到结果");
return;
}
System.out.println("搜索结果");
result.forEach(c->{
System.out.println(c.getId());
System.out.println(c.getScore());
System.out.println(c.getText());
});
}
测试用例运行结果
PDF 除了按页读取的PagePdfDocumentReader ,还有ParagraphPdfDocumentReader 按大纲读取,但是很多PDF文件不规范,没有大纲标题,会导致读取失败。

向量搜索
按照文本的向量搜索

java
List<Document> result = vectorStore.similaritySearch("谁创办了Docker");
if(null==result){
System.out.println("没有找到结果");
return;
}
System.out.println("搜索结果");
result.forEach(c->{
System.out.println(c.getId());
System.out.println(c.getScore());
System.out.println(c.getText());
});
这里搜出了4页,但是实际上一些结果并不相关,我们并不想要关联度不是很高的结果。
增加配置的向量搜索
> 使用vectorStore,我们已经配置了向量模型,故在写向量和搜索向量时,并不需要我们显式的进行向量化操作,而是由其内部完成向量化转换。
java
// 8. 验证写入结果
System.out.println("成功写入 " + documents.size() + " 个文档块到向量数据库");
SearchRequest request = SearchRequest.builder()
.query("谁创办了Docker") //匹配关键词
.topK(2) //相似度最高的前几名
.similarityThreshold(0.7) //相似度阈值
.filterExpression("file_name =='40、狂神说Docker.pdf'") //过滤项目,表示搜索元数据里面文件名是40、狂神说Docker.pdf的文档
.build();
// List<Document> result = vectorStore.similaritySearch("谁创办了Docker");
List<Document> result = vectorStore.similaritySearch(request);
if(null==result){
System.out.println("没有找到结果");
return;
}
System.out.println("搜索结果");
result.forEach(c->{
System.out.println(c.getId());
System.out.println(c.getScore());
System.out.println(c.getText());
});
经过这些过滤条件,我们可以看到只搜索到一条记录。
