Spring AI(11) :ChatPDF-向量数据库、PDF处理、向量写入和向量搜索

本章代码已分享至Gitee:https://gitee.com/lengcz/ai-study.git

文章目录

向量数据库

向量数据库的核心作用是‌实现语义层面的相似性检索‌,区别于传统数据库的字面精确匹配,能快速找到"含义最贴近"的数据,是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());
        });

经过这些过滤条件,我们可以看到只搜索到一条记录。

相关推荐
人工智能培训5 分钟前
从“捏泥人”到“造世界”:3D生成式AI的技术跃迁与产业落地
大数据·人工智能·学习·生活·ai写作
广州灵眸科技有限公司10 分钟前
瑞芯微(EASY EAI)RV1126B display
开发语言·数据库·人工智能·科技·嵌入式硬件
极客互动API14 分钟前
企业微信 AI 智能客服实战:Spring Boot+Vue 接入豆包、扣子、DeepSeek
java·人工智能·微信·企业微信
今天AI了吗15 分钟前
Codex使用技巧:深度解析 Plan Mode 与 Goal Mode
java·网络·人工智能·架构·java-ee
FX1317887KP_18 分钟前
AI陪练正在重塑KET PET FCE口语备考,传统外教课还有必要吗?
人工智能·小程序·ket口语·pet口语·fce备考·剑桥英语
天远Date Lab18 分钟前
零信任架构实战:基于天远全能个人大数据报告构建自动化核心KYC网关
大数据·人工智能·架构·自动化
智购科技智能售货柜19 分钟前
2026自动售货机商品掉落声学计数方案:从麦克风到频谱识别的工程实践~YH
人工智能·算法
QXWZ_IA20 分钟前
输电线路沉降监测用什么技术?三种高精度路线对比与精度解析
人工智能·科技
盛世宏博智慧档案22 分钟前
基于PLC与物联网网关的档案库房温湿度超标自动联动控制实现思路(含拓扑图与协议对接)
大数据·人工智能·物联网
CV山月23 分钟前
《DPO 算法详解:不训练奖励模型,如何让大模型直接学会人类偏好?》
人工智能·经验分享·python·大模型·强化学习·研究生