【微服务】SpringBoot 整合Redis Stack 构建本地向量数据库相似性查询

目录

一、前言

二、向量数据库介绍

[2.1 什么是向量数据库](#2.1 什么是向量数据库)

[2.2 向量数据库特点](#2.2 向量数据库特点)

[2.3 向量数据库使用场景](#2.3 向量数据库使用场景)

三、常用的向量数据库解决方案

[3.1 Milvus](#3.1 Milvus)

[3.1.1 Milvus是什么](#3.1.1 Milvus是什么)

[3.1.2 Milvus主要特点](#3.1.2 Milvus主要特点)

[3.2 Faiss](#3.2 Faiss)

[3.2.1 Faiss是什么](#3.2.1 Faiss是什么)

[3.2.2 Faiss主要特点](#3.2.2 Faiss主要特点)

[3.3 Pinecone](#3.3 Pinecone)

[3.3.1 Pinecone是什么](#3.3.1 Pinecone是什么)

[3.3.2 Pinecone主要特点](#3.3.2 Pinecone主要特点)

[3.4 Weaviate](#3.4 Weaviate)

[3.4.1 Weaviate介绍](#3.4.1 Weaviate介绍)

[3.4.2 Weaviate主要特点](#3.4.2 Weaviate主要特点)

[3.5 Redis Stack](#3.5 Redis Stack)

[3.5.1 Redis Stack介绍](#3.5.1 Redis Stack介绍)

[3.5.2 Redis Stack核心模块](#3.5.2 Redis Stack核心模块)

[3.5.3 Redis Stack主要特点](#3.5.3 Redis Stack主要特点)

[3.5.4 Redis Stack应用场景](#3.5.4 Redis Stack应用场景)

四、Redis向量数据库介绍

[4.1 redis向量数据库是什么](#4.1 redis向量数据库是什么)

[4.2 向量检索核心原理](#4.2 向量检索核心原理)

[4.2.1 匹配原理](#4.2.1 匹配原理)

[4.2.2 具体实现过程](#4.2.2 具体实现过程)

[五、整合springboot 实现向量数据库相似性搜索](#五、整合springboot 实现向量数据库相似性搜索)

[5.1 前置准备](#5.1 前置准备)

[5.1.1 docker搭建Redis-Stack](#5.1.1 docker搭建Redis-Stack)

[5.1.2 导入maven依赖](#5.1.2 导入maven依赖)

[5.1.3 获取apikey](#5.1.3 获取apikey)

[5.1.4 添加配置文件](#5.1.4 添加配置文件)

[5.2 文本嵌入代码实现过程](#5.2 文本嵌入代码实现过程)

[5.2.1 添加一个测试接口](#5.2.1 添加一个测试接口)

[5.3 ETL Pipeline](#5.3 ETL Pipeline)

[5.3.1 Spring AI ETL 介绍](#5.3.1 Spring AI ETL 介绍)

[5.3.2 Spring AI 处理ETL完整过程](#5.3.2 Spring AI 处理ETL完整过程)

[5.3.3 Spring AI ETL 技术框架](#5.3.3 Spring AI ETL 技术框架)

[5.3.3.1 读取器 DocumentReader](#5.3.3.1 读取器 DocumentReader)

[5.3.3.2 文档转换器 DocumentTransformer](#5.3.3.2 文档转换器 DocumentTransformer)

[5.3.3.3 文档写入器 DocumentWriter](#5.3.3.3 文档写入器 DocumentWriter)

[5.4 Spring AI 文档读取操作演示](#5.4 Spring AI 文档读取操作演示)

[5.4.1 文件读取代码演示](#5.4.1 文件读取代码演示)

[5.5 Spring AI 文档转换操作演示](#5.5 Spring AI 文档转换操作演示)

[5.5.1 添加测试接口](#5.5.1 添加测试接口)

[5.6 文档存储](#5.6 文档存储)

[5.6.1 导入依赖文件](#5.6.1 导入依赖文件)

[5.6.2 配置redis信息](#5.6.2 配置redis信息)

[5.6.3 增加一个redis的向量数据库配置类](#5.6.3 增加一个redis的向量数据库配置类)

[5.6.4 增加嵌入文档接口](#5.6.4 增加嵌入文档接口)

[5.6.5 增加文档检索接口](#5.6.5 增加文档检索接口)

六、写在文末


一、前言

AI工具的使用让数据检索的需求场景变得越来越多,也越来越复杂,传统的关系型数据库尽管可以满足日常各类关系数据的存储,但是遇到一些文档类型,非结构化的数据时,其作用和效果就会打折扣,而且数据不仅仅是存储的需要,也需要能够满足数据分析的场景,这种情况下,就可以考虑使用向量数据库了。

二、向量数据库介绍

2.1 什么是向量数据库

向量数据库是一种优化后的数据库系统,专门设计用于高效地存储和检索高维向量数据。这些向量数据通常是从原始数据(如文本、图像、音频等)中提取的特征表示。向量数据库的核心优势在于其能够快速地进行相似性搜索,即找到与给定向量最相似的向量。

2.2 向量数据库特点

向量数据库主要具备如下特征:

  • 高效相似性搜索

    • 支持多种相似性度量,如欧氏距离(L2)、余弦相似度、Jaccard 相似度等。

    • 使用特殊的索引结构(如局部敏感哈希LSH、近似最近邻ANN等)来加速相似性搜索。

  • 高维数据处理

    • 优化了高维向量数据的存储和检索,能够在大规模数据集中高效地进行相似性搜索。

    • 支持分布式存储和计算,能够轻松扩展到多个节点。

  • 灵活的数据模型

    • 通常采用无模式或半结构化数据模型,允许灵活地存储和处理不同类型的向量数据。

    • 支持元数据存储,可以将向量数据与相关的元数据(如标签、时间戳等)一起存储。

  • 实时和批量处理

    • 支持实时插入和查询,适用于在线推荐系统等实时应用场景。

    • 也支持批量数据插入和查询,适用于离线数据分析和处理。

2.3 向量数据库使用场景

在下面的一些场景中可以考虑使用向量数据库

  • 推荐系统

    • 通过用户行为数据生成用户和物品的向量表示,用于推荐相似的物品或用户。

    • 例如,电商网站可以根据用户的浏览和购买历史生成用户向量,推荐相似的商品。

  • 图像搜索

    • 将图像转换为向量表示,用于相似图像的搜索和检索。

    • 例如,搜索引擎可以根据上传的图片找到相似的图片。

  • 生物信息学

    • 将DNA序列或其他生物数据转换为向量表示,用于基因相似性搜索和分析。

    • 例如,研究人员可以使用向量数据库来寻找与已知基因序列相似的新基因。

  • 自然语言处理

    • 将文本转换为向量表示,用于文本相似性搜索、情感分析、机器翻译等任务。

    • 例如,聊天机器人可以根据用户输入的文本生成向量,找到最合适的回复。

  • 广告推荐

    • 根据用户的兴趣和行为生成用户向量,推荐相关的广告。

    • 例如,社交媒体平台可以根据用户的兴趣生成用户向量,推荐相关的广告内容。

三、常用的向量数据库解决方案

向量数据库的选择也比较多,下面列举几种常用的向量数据库解决方案。

3.1 Milvus

3.1.1 Milvus是什么

Milvus 是一个高性能的向量数据库,由 Zilliz 开发并维护。它支持多种相似性度量(如欧氏距离、余弦相似度等),并使用高效的索引结构(如 IVF、HNSW 等)来加速相似性搜索。Milvus 可以处理大规模的向量数据集,并支持分布式部署,适用于多种应用场景。Milvus 在推荐系统、图像搜索、自然语言处理等领域表现出色,能够快速地进行相似性搜索,找到与给定向量最相似的向量。

git地址 : GitHub - milvus-io/milvus: A cloud-native vector database, storage for next generation AI applications

3.1.2 Milvus主要特点

Milvus具有如下特点:

  • 高效的相似性搜索

    • 多种相似性度量:支持欧氏距离(L2)、余弦相似度、内积等相似性度量。

    • 高效的索引结构:支持多种索引结构,如 IVF(Inverted File)、HNSW(Hierarchical Navigable Small World)等,能够显著加速相似性搜索。

  • 使用简单

    • 丰富的 API 和 SDK:提供多种编程语言的 SDK,包括 Python、Java、C++、Go 等,方便开发者集成。

    • 详细的文档和社区支持:提供详细的文档和活跃的社区支持,帮助开发者快速上手。

  • 多样化的数据源支持

    • 多种数据源:支持多种数据源,可以与 TensorFlow、PyTorch 等深度学习框架集成,方便数据预处理和特征提取。
  • 扩展性和可伸缩性好

    • 分布式部署:支持分布式部署,能够处理大规模数据集,支持水平扩展。

    • 高可用性:支持自动故障恢复和数据备份,保证系统的高可用性。

3.2 Faiss

3.2.1 Faiss是什么

Faiss 是一个开源库,专注于大规模向量相似性搜索和聚类。它支持多种相似性度量(如欧氏距离、余弦相似度等),并使用高效的索引结构(如 IVF(Inverted File)、HNSW(Hierarchical Navigable Small World)等)来加速搜索过程。Faiss 可以在 CPU 和 GPU 上运行,适用于多种应用场景。

git地址 : GitHub - facebookresearch/faiss: A library for efficient similarity search and clustering of dense vectors.

3.2.2 Faiss主要特点

Faiss具有如下特点:

  • 高效的相似性搜索

    • 多种相似性度量:支持欧氏距离(L2)、余弦相似度、内积等相似性度量。

    • 高效的索引结构:支持多种索引结构,如 IVF(Inverted File)、HNSW(Hierarchical Navigable Small World)、PQ(Product Quantization)等,能够显著加速相似性搜索。

  • 高性能

    • CPU 和 GPU 支持:可以在 CPU 和 GPU 上运行,利用硬件加速提高搜索性能。

    • 内存优化:对内存使用进行了优化,能够在有限的内存中处理大规模数据集。

  • 灵活性好

    • 多种索引方法:提供了多种索引方法,可以根据具体需求选择合适的索引结构。

    • 自定义索引:支持自定义索引结构和搜索算法,满足特定应用的需求。

  • 易于使用

    • 丰富的 API:提供了 C++ 和 Python API,方便开发者集成。

    • 详细的文档和社区支持:提供详细的文档和活跃的社区支持,帮助开发者快速上手。

3.3 Pinecone

3.3.1 Pinecone是什么

Pinecone 是一个云原生的向量数据库,专为高效地存储和检索大规模向量数据而设计。它旨在简化向量数据的存储和检索过程,提供高性能的相似性搜索功能。Pinecone 提供了高性能的相似性搜索功能,支持实时和批量处理,适用于推荐系统、图像搜索、自然语言处理等多种应用场景。

官方地址:The vector database to build knowledgeable AI | Pinecone

3.3.2 Pinecone主要特点

Pinecone具备如下特点:

  • 高性能

    • 高效的相似性搜索:支持多种相似性度量,如余弦相似度、欧氏距离等,使用高效的索引结构(如 HNSW、IVF 等)来加速搜索过程。

    • 低延迟:优化了搜索性能,能够在毫秒级别内返回结果,适用于实时应用场景。

  • 使用简单

    • 简单的 API 和 SDK:提供丰富的 API 和 SDK,支持多种编程语言(如 Python、JavaScript 等),方便开发者集成。

    • 详细的文档和社区支持:提供详细的文档和活跃的社区支持,帮助开发者快速上手。

  • 扩展性和可伸缩性好

    • 云原生:提供托管服务,支持自动扩展和故障恢复,保证系统的高可用性。

    • 水平扩展:支持水平扩展,能够处理大规模数据集,适用于企业级应用。

  • 多样化的数据源支持

    • 多种数据源:支持多种数据源,可以与 TensorFlow、PyTorch 等深度学习框架集成,方便数据预处理和特征提取。

3.4 Weaviate

3.4.1 Weaviate介绍

Weaviate 是一个开源的向量搜索引擎,由 Semitechnologies 开发并维护。它不仅支持高效的向量数据存储和检索,还结合了图数据模型,使其在处理复杂数据关系方面表现出色。Weaviate 适用于推荐系统、图像搜索、自然语言处理等多种应用场景。Weaviate 支持多种相似性度量(如余弦相似度、欧氏距离等),并使用高效的索引结构来加速搜索过程。Weaviate 提供了丰富的 API 和 SDK,支持多种编程语言,方便开发者集成。

3.4.2 Weaviate主要特点

Weaviate具备如下特点

  • 图数据模型

    • 图数据模型:支持图数据模型,可以表示和查询复杂的数据关系。

    • 灵活的数据模型:支持多种数据类型和格式,可以轻松适应各种用例。

  • 高效的相似性搜索

    • 多种相似性度量:支持余弦相似度、欧氏距离等相似性度量。

    • 高效的索引结构:使用高效的索引结构(如 HNSW)来加速相似性搜索。

  • 使用简单

    • 丰富的 API 和 SDK:提供丰富的 API 和 SDK,支持多种编程语言(如 Python、JavaScript、Go 等),方便开发者集成。

    • 详细的文档和社区支持:提供详细的文档和活跃的社区支持,帮助开发者快速上手。

  • 扩展性和可伸缩性好

    • 云原生支持:提供托管服务,支持自动扩展和故障恢复,保证系统的高可用性。

    • 水平扩展:支持水平扩展,能够处理大规模数据集,适用于企业级应用。

  • 查询语言

    • 支持 GraphQL:提供强大的 GraphQL 查询功能,支持复杂的查询和过滤条件。

3.5 Redis Stack

3.5.1 Redis Stack介绍

Redis Stack 是 Redis 的一个扩展版本,它不仅包含了 Redis 的核心功能,还增加了多个模块,如 RediSearch(全文搜索)、RedisGraph(图数据库)、RedisTimeSeries(时间序列数据库)和 RedisAI(AI推理)。这些模块使得 Redis Stack 成为一个功能更加强大的数据库系统,适用于多种应用场景。

3.5.2 Redis Stack核心模块

Redis Stack核心模块主要包括下面几块

  • RediSearch

    • 全文搜索:提供全文搜索功能,支持复杂的查询和过滤条件。

    • 向量搜索:支持向量数据的存储和相似性搜索,适用于推荐系统、图像搜索等场景。

    • 性能优化:使用倒排索引和 BM25 算法优化搜索性能。

  • RedisGraph

    • 图数据库:提供图数据模型,支持节点和边的存储和查询。

    • Cypher 查询语言:支持 Cypher 查询语言,方便进行复杂的图数据查询。

    • 高性能:优化了图数据的存储和查询性能。

  • RedisTimeSeries

    • 时间序列数据:提供时间序列数据的存储和查询功能,适用于监控、日志分析等场景。

    • 压缩和聚合:支持数据压缩和聚合,节省存储空间和提高查询性能。

  • RedisAI

    • AI 推理:提供 AI 推理功能,支持 TensorFlow、PyTorch 等深度学习框架。

    • 模型管理和执行:支持模型的加载、管理和执行,适用于实时推理和预测。

3.5.3 Redis Stack主要特点

Redis Stack主要具备如下特点:

  • 高性能

    • 内存优化:Redis Stack 优化了内存使用,能够在有限的内存中处理大规模数据集。

    • 低延迟:Redis Stack 提供低延迟的数据访问,适用于实时应用场景。

  • 使用简单

    • 丰富的 API 和 SDK:提供丰富的 API 和 SDK,支持多种编程语言(如 Python、Java、C++、Go 等),方便开发者集成。

    • 详细的文档和社区支持:提供详细的文档和活跃的社区支持,帮助开发者快速上手。

  • 多样化的数据源支持

    • 多种数据源:支持多种数据源,可以与 TensorFlow、PyTorch 等深度学习框架集成,方便数据预处理和特征提取。
  • 扩展性和可伸缩性

    • 分布式部署:支持分布式部署,能够处理大规模数据集,支持水平扩展。

    • 高可用性:支持自动故障恢复和数据备份,保证系统的高可用性。

3.5.4 Redis Stack应用场景

Redis Stack主要有下面的应用场景

  • 全文搜索

    • 电子商务:支持商品搜索和推荐。

    • 内容管理系统:支持文章和文档的搜索和管理。

  • 图数据库

    • 社交网络:支持用户关系和社交图谱的存储和查询。

    • 推荐系统:支持基于图数据的推荐算法。

  • 时间序列数据

    • 监控系统:支持系统监控和日志分析。

    • 物联网:支持 IoT 设备的数据收集和分析。

  • AI 推理

    • 实时推荐:支持基于 AI 的实时推荐系统。

    • 图像识别:支持图像识别和分类。

四、Redis向量数据库介绍

4.1 redis向量数据库是什么

Redis 是一个开源(BSD 许可)的内存数据结构存储,用作数据库、缓存、消息代理和流式处理引擎。Redis 提供数据结构,例如字符串、哈希、列表、集合、带范围查询的有序集合、位图、超对数日志、地理空间索引和流。

Redis 搜索和查询, 扩展了 Redis OSS 的核心功能,因此可以将 Redis 用作向量数据库

  • 在哈希或 JSON 文档中存储向量和关联的元数据

  • 检索向量

  • 执行向量搜索

4.2 向量检索核心原理

向量检索(Vector Search)的核心原理是通过将文本或数据表示为高维向量,并在查询时根据向量的相似度进行搜索。具体来说,向量检索过程涉及以下核心几点。

4.2.1 匹配原理

  • 检索的核心是将文本或数据转换成向量,在高维向量空间中查找与查询最相似的向量。

  • 在存储数据时将指定的字段通过嵌入模型生成了向量。

  • 在检索时,查询文本被向量化,然后与 Redis 中存储的向量进行相似度比较,找到相似度最高的向量(即相关的文档)。

技术关键点:

  • 嵌入模型

    • 将文本转换成向量。
  • 相似度计算

    • 通过余弦相似度或欧几里得距离来度量相似性。
  • Top K

    • 返回相似度最高的 K 个文档。

4.2.2 具体实现过程

在代码中操作时,主要包括下面几步:

  • 向量化数据:

    • 当你将 JSON 中的字段存入 Redis 时,向量化工具(例如 vectorStore)会将指定的字段转换为高维向量。每个字段的内容会通过某种嵌入模型(如 Word2Vec、BERT、OpenAI Embeddings 等)转换成向量表示。每个向量表示的是该字段内容的语义特征。
  • 搜索时向量生成:

    • 当执行 SearchRequest.query(message) 时,系统会将输入的 message 转换为一个查询向量。这一步是通过同样的嵌入模型,将查询文本转换为与存储在 Redis 中相同维度的向量。
  • 相似度匹配:

    • vectorStore.similaritySearch(request) 函数使用了一个向量相似度计算方法来查找最相似的向量。这通常是通过 余弦相似度 或 欧几里得距离 来度量查询向量和存储向量之间的距离。然后返回与查询最相似的前 K 个文档,即 withTopK(topK) 所指定的 K 个最相关的结果。
  • 返回匹配的文档:

    • 匹配的结果是根据相似度得分排序的 List<Document>。这些文档是你最初存储在 Redis 中的记录,包含了 JSON 中指定的字段。

五、整合springboot 实现向量数据库相似性搜索

接下来使用Redis Stack作为向量数据库,并整合springboot 实现向量数据库相似性搜索的过程。

5.1 前置准备

5.1.1 docker搭建Redis-Stack

使用下面的docker命令搭建Redis-Stack

bash 复制代码
docker run -d --name redis-stack -v /redis-data:/data -p 6379:6379 -p 8001:8001 redis/redis-stack:latest

也可以使用下面的docker compose命令启动容器

bash 复制代码
version: '3'
services:
  redis-stack:
    image: redis/redis-stack
    ports:
      - 6379:6379

  redis-insight:
    image: redislabs/redisinsight:latest
    ports:
      - 5540:5540

可以通过 IP:8001 访问 Redis-Stack 的web控制台,这里在后面将会用于存储程序中的文本嵌入数据

5.1.2 导入maven依赖

在你的maven工程中导入如下依赖

java 复制代码
<properties>
    <maven.compiler.source>17</maven.compiler.source>
    <maven.compiler.target>17</maven.compiler.target>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>3.2.4</version>
    <relativePath/>
</parent>

<dependencies>

    <dependency>
        <groupId>com.alibaba.cloud.ai</groupId>
        <artifactId>spring-ai-alibaba-starter</artifactId>
        <version>1.0.0-M2.1</version>
    </dependency>

    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>2.0.35</version>
    </dependency>

    <dependency>
        <groupId>com.squareup.okhttp3</groupId>
        <artifactId>okhttp</artifactId>
        <version>4.12.0</version>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <scope>provided</scope>
    </dependency>

    <!-- https://mvnrepository.com/artifact/com.alibaba/dashscope-sdk-java -->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>dashscope-sdk-java</artifactId>
        <version>2.16.9</version>
    </dependency>

    <dependency>
        <groupId>org.apache.httpcomponents</groupId>
        <artifactId>httpclient</artifactId>
        <version>4.5.13</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/io.milvus/milvus-sdk-java -->
    <dependency>
        <groupId>io.milvus</groupId>
        <artifactId>milvus-sdk-java</artifactId>
        <version>2.4.6</version>
    </dependency>

</dependencies>

<repositories>
    <repository>
        <id>spring-milestones</id>
        <name>Spring Milestones</name>
        <url>https://repo.spring.io/milestone</url>
        <snapshots>
            <enabled>false</enabled>
        </snapshots>
    </repository>
</repositories>

5.1.3 获取apikey

下文中将会先演示使用云厂商提供的向量数据库,所以这里使用百炼平台的,需要先获取apikey

获取apikey,可以去阿里云的百炼平台获取,然后在模型广场中向量模型那里选择一种文本向量使用

5.1.4 添加配置文件

在工程的配置文件中增加下面的配置内容

java 复制代码
server:
  port: 8081


spring:
  ai:
    dashscope:
      api-key: 你的apikey

      embedding:
        options:
          model: text-embedding-v2

5.2 文本嵌入代码实现过程

如何用一段话去数据库查找数据?答案是向量求相似度。相似度越高,返回的数据就越靠前,比如大家熟知的搜索引擎es,你输入一段文本去查询,es会根据算分将得分最高的文档放在前面返回给你,在大模型中,嵌入模型就可以帮我们做到这件事,所以第一件事情需要将文本中的句子向量化,然后和向量数据库中的向量进行比较,找到最相似的向量。下面使用代码演示下这个过程。

5.2.1 添加一个测试接口

添加一个测试接口,参考下面的代码

java 复制代码
package com.congge.web;

import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.embedding.EmbeddingResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;
import java.util.Map;

@RestController
@Slf4j
public class DocumentController {

    private final EmbeddingModel embeddingModel;

    @Autowired
    public DocumentController(EmbeddingModel embeddingModel) {
        this.embeddingModel = embeddingModel;
    }

    @GetMapping("/ai/embedding")
    public Map embed(@RequestParam(value = "message", defaultValue = "Tell me a joke") String message) {
        EmbeddingResponse embeddingResponse = this.embeddingModel.embedForResponse(List.of(message));
        return Map.of("embedding", embeddingResponse);
    }

    //localhost:8081/embedding
    @GetMapping("/embedding")
    public Object embeddingTest() {
        // 文本嵌入
        float[] embed = embeddingModel.embed("你好,我是小码农叔叔");
        log.info("文本转换得到的向量: {}", embed);
        return embed;
    }

}

两个接口均可用于测试,选择第二个测试,请求之后,返回了很多向量的参数

5.3 ETL Pipeline

ETL是提取、转换、加载的缩写,从原始的文档到数据库需要经历提取(.doc、.ppt、.xlsx等)、转换(数据结构化、清理数据、数据分块)、写入向量数据库。这个过程可以进行多种处理,确保最后的数据适合AI问答。

SpringAI提供了ETL框架。它是搭建知识库框架的基石。

5.3.1 Spring AI ETL 介绍

在AI应用程序中,数据处理是至关重要的一部分。Spring AI提供了一个强大的ETL框架,帮助开发者高效地进行数据提取、转换和加载操作。通过这个框架,你可以轻松地将数据准备好用于AI模型的训练和推理。

5.3.2 Spring AI 处理ETL完整过程

与传统的etl过程稍有不同,springai 中etl 的完整过程如下:

  • 数据提取

    • 数据提取是ETL流程的第一步。在这个阶段,你需要从各种数据源中提取原始数据。Spring AI支持多种数据源,包括数据库、文件系统、API等。
  • 数据转换

    • 数据转换是ETL流程的第二步。在这个阶段,你需要将原始数据转换为适合AI模型使用的格式。Spring AI提供了多种数据转换工具,帮助你高效地处理数据。
  • 向量化数据

    • 对于AI模型来说,向量化数据是必不可少的步骤。只有经过向量化之后的数据才能在后续的检索中正常检索出结果。
  • 数据加载

    • 数据加载是ETL流程的最后一步。在这个阶段,你需要将转换后的数据加载到目标存储系统中,以便AI模型使用。Spring AI支持将数据加载到多种目标存储系统中。

5.3.3 Spring AI ETL 技术框架

5.3.3.1 读取器 DocumentReader

DocumentReader ,文档读取器:

  • 用于读取文档,比如PDF、Word、Excel等

    • 如:JsonReader(读取JSON),TextReader(读取文本),PagePdfDocumentReader(读取PDF),TikaDocumentReader(读取各种文件,大部分都可以支持.pdf,.xlsx,.docx,.pptx,.md,.json等)。

    • 这些reader都是DocumentReader的实现类。

5.3.3.2 文档转换器 DocumentTransformer

文档转换器,处理文档:

  • TextSplitter(文档切割成小块),ContentFormatTransformer(将文档变成键值对),SummaryMetadataEnricher(使用大模型总结文档),KeywordMetadataEnricher(使用大模型提取文档关键词)
5.3.3.3 文档写入器 DocumentWriter

文档写入器:

  • 将文档写入向量数据库或者本地文件。

  • VectorStore(向量数据库写入器),FileDocumentWriter(文件写入器)。

使用这几个组件,完整的执行流程如下:

5.4 Spring AI 文档读取操作演示

5.4.1 文件读取代码演示

TikaDocumentReader 比较全能,大部分文件都可读取,支持的文件格式可以参考官方文档。如果是比较个性化文档的场景,最好自己实现一个Reader,便于业务扩展。pom文件中导入下面的依赖。

java 复制代码
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-tika-document-reader</artifactId>
        </dependency>

从输入流读取文件,参考下面的接口代码

java 复制代码
@SneakyThrows
@PostMapping("read/multipart-file")
public void readMultipartFile(@RequestParam MultipartFile file) {
    // 从IO流中读取文件
    Resource resource = new InputStreamResource(file.getInputStream());
    List<Document> documents = new TikaDocumentReader(resource)
            .read();
}

上传一个本地的文档,接口测试效果,可以看到被分割成很多片段了

从本地文件读取,参考下面的接口代码

java 复制代码
/**
 * 从本地文件读取
 * @return
 */
@GetMapping("/read/from-local-file")
public Object readLocalFile() {
    FileSystemResource resource = new FileSystemResource("E:\\工作空间\\wzlocal\\Java编码规范V1.0.pdf");
    List<Document> documents = new TikaDocumentReader(resource)
            .read();
    return documents;
}

调用一下接口,使用相同的文件,得到类似的效果

5.5 Spring AI 文档转换操作演示

在上一步的操作中,读取返回的是Document对象,而是DocumentETL Pipeline的核心对象,它包含了文档的元数据和内容。接下来就需要对文档进行转换。此时就要用到内容转换器。包括内容转换器和元数据转换器。

内容转换器

  • TokenTextSplitter:可以把内容切割成更小的块方便RAG的时候提升响应速度节省Token。

  • ContentFormatTransformer:可以把元数据的内容变成键值对字符串。

元数据转换器

  • SummaryMetadataEnricher:使用大模型总结文档。会在元数据里面增加一个summary字段。

  • KeywordMetadataEnricher:使用大模型提取文档关键词。可以在元数据里面增加一个keywords字段。

5.5.1 添加测试接口

参考下面的代码

java 复制代码
/**
 * 分割后的文档列表  localhost:8081/doc/split
 * @param file
 * @return
 * @throws Exception
 */
@PostMapping("/doc/split")
public Object docSplit(@RequestParam MultipartFile file) throws Exception{
    InputStreamResource inputStreamResource = new InputStreamResource(file.getInputStream());
    List<Document> documentList = new TikaDocumentReader(inputStreamResource).read();
    // 分割后的文档列表
    List<Document> splitDocList = new TokenTextSplitter().split(documentList);
    List<String> contentList = splitDocList.stream().map(Document::getContent).collect(Collectors.toList());
    return contentList;
}

测试一下接口,可以看到被转换后的文档分割成多个片段

5.6 文档存储

经过前面的步骤,我们得到了一个文档列表,为了方便后续的文档搜索,需要将文档进行存储,文档存储到哪里去呢?即向量数据库。上面准备阶段搭建的Redis-Stack即是用于做向量数据库使用的。下面看代码中的操作过程。

5.6.1 导入依赖文件

导入下面的依赖坐标

java 复制代码
<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-tika-document-reader</artifactId>
    <version>1.0.0-M3</version>
</dependency>

<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-redis-store</artifactId>
    <version>1.0.0-M3</version>
</dependency>

<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
</dependency>

5.6.2 配置redis信息

在配置文件中添加redis的信息

java 复制代码
spring:
  ai:
    dashscope:
      api-key: 你的apikey

      embedding:
        options:
          model: text-embedding-v2
    vectorstore:
      redis:
        uri: redis://IP:6379

  data:
    redis:
      database: 0
      timeout: 10s
      lettuce:
        pool:
          # 连接池最大连接数
          max-active: 200
          # 连接池最大阻塞等待时间(使用负值表示没有限制)
          max-wait: -1ms
          # 连接池中的最大空闲连接
          max-idle: 10
          # 连接池中的最小空闲连接
          min-idle: 0
      repositories:
        enabled: false

      host: redis地址

5.6.3 增加一个redis的向量数据库配置类

如果在你的项目里面有用到redis,需要先禁用RedisVectorStoreAutoConfiguration。这是SpringAI自动配置RedisStack的向量数据库连接,会导致Redis的连接配置冲突。参考下面的代码。

java 复制代码
package com.congge.config;

import lombok.AllArgsConstructor;
import org.springframework.ai.autoconfigure.vectorstore.redis.RedisVectorStoreAutoConfiguration;
import org.springframework.ai.autoconfigure.vectorstore.redis.RedisVectorStoreProperties;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.vectorstore.RedisVectorStore;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.data.redis.RedisConnectionDetails;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import redis.clients.jedis.JedisPooled;

@Configuration
// 禁用SpringAI提供的RedisStack向量数据库的自动配置,会和Redis的配置冲突。
@EnableAutoConfiguration(exclude = {RedisVectorStoreAutoConfiguration.class})
// 读取RedisStack的配置信息
@EnableConfigurationProperties({RedisVectorStoreProperties.class})
@AllArgsConstructor
public class RedisVectorConfig {

    /**
     * 创建RedisStack向量数据库
     *
     * @param embeddingModel 嵌入模型
     * @param properties     redis-stack的配置信息
     * @return vectorStore 向量数据库
     */
    @Bean
    public VectorStore vectorStore(EmbeddingModel embeddingModel,
                                   RedisVectorStoreProperties properties,
                                   RedisConnectionDetails redisConnectionDetails) {
        RedisVectorStore.RedisVectorStoreConfig config = RedisVectorStore.RedisVectorStoreConfig.builder().withIndexName(properties.getIndex()).withPrefix(properties.getPrefix()).build();
        return new RedisVectorStore(config, embeddingModel,
                new JedisPooled(redisConnectionDetails.getStandalone().getHost(),
                        redisConnectionDetails.getStandalone().getPort()
                        , redisConnectionDetails.getUsername(),
                        redisConnectionDetails.getPassword()),
                properties.isInitializeSchema());
    }
}

5.6.4 增加嵌入文档接口

在上面的VectorStore配置中我们提供了EmbeddingModel,调用vectorStore.add(splitDocuments)底层会把文档给EmbeddingModel把文本变成向量然后再存入向量数据库。参考下面的代码。

java 复制代码
/**
 * 文档保存到向量数据库   localhost:8081/doc/embedding
 * @param file
 * @return
 * @throws Exception
 */
@PostMapping("/doc/embedding")
public Object docEmbedding(@RequestParam MultipartFile file) throws Exception{
    TikaDocumentReader tikaDocumentReader = new TikaDocumentReader(new InputStreamResource(file.getInputStream()));
    List<Document> splitDocuments = new TokenTextSplitter().apply(tikaDocumentReader.read());
    // 存入向量数据库,这个过程会自动调用embeddingModel,将文本变成向量存入
    vectorStore.add(splitDocuments);
    return true;
}

调用一下接口

接口执行成功后,在Redis-Stack的控制台界面可以看到数据存入了redis中

5.6.5 增加文档检索接口

数据存入进去之后接下来就可以进行搜索了,添加下面文档检索的接口

java 复制代码
/**
 * 关键字检索文档  localhost:8081/doc/query?keyword=面向对象
 * @param keyword
 * @return
 */
@GetMapping("/doc/query")
public List<Document> query(@RequestParam String keyword) {
    List<Document> documentList = vectorStore.similaritySearch(keyword);
    return documentList;
}

六、写在文末

本文通过较大的篇幅详细介绍了常用的向量数据库解决方案,并通过搭建redis stack环境,结合代码演示了如何基于redis stack作为向量数据库进行使用,希望对看到的同学有用,本篇到此介绍,感谢观看。

相关推荐
桦仔3 天前
全新向量数据库SQL Server 2025:带你迈入AI驱动的数据未来
向量数据库·ai数据库·sql server2025
水中加点糖11 天前
使用Spring AI中的RAG技术,实现私有业务领域的大模型系统
人工智能·function call·向量数据库·rag·springai·私有大模型·embedding模型
不会编程的猫星人12 天前
向量数据库PGVECTOR安装
数据库·postgresql·向量数据库
讲文明的喜羊羊拒绝pua24 天前
AIGC学习笔记(2)——AI大模型开发工程师
llm·aigc·transformer·向量数据库·ai大模型开发
陌北v11 个月前
Milvus 与 Faiss:选择合适的向量数据库
milvus·faiss·向量数据库
桦仔1 个月前
老司机带你聊聊向量数据库
向量数据库·关系型数据库·向量数据库解释
dept1231 个月前
python,pycharm,pytorch,向量数据库,环境搭建记录
pytorch·python·pycharm·向量数据库
python_知世1 个月前
知识图谱融入向量数据库,带来RAG效果飞升
数据库·人工智能·llm·知识图谱·大语言模型·向量数据库·rag
Linux猿2 个月前
828华为云征文 | 云服务器Flexus X实例:向量数据库 pgvector 部署,实现向量检索
华为云·向量数据库·云服务器·pgvector·华为云服务器·云服务器flexus x实例