Spring AI 如何集成向量数据库入门:以ChromaDB为例详细解析

后端 潘老师 2个月前 (02-21) 230 ℃ (0) 扫码查看

在人工智能领域,向量数据库是一个关键技术,它能高效存储向量嵌入,并实现相似性搜索。本文以ChromaDB为例,深入介绍Spring AI中向量数据库的使用,帮助读者快速掌握相关技术,将其应用到实际项目中。

一、什么是向量数据库

向量(也叫嵌入向量)是一个由数字组成的长数组,它能用来表示单词、句子、文件、音视频数据等各种对象。数组中的每个数字,都代表了数据的某个独特特征或属性,比如情感的积极程度、强度、上下文等。通过计算两个向量之间的距离,我们就能判断不同对象之间的相关性,这个过程就是语义搜索。

向量数据库是一种特殊的数据库,它能大规模、低延迟且安全地存储高维向量数据。下面简单介绍下向量数据库的工作原理:

  • 数据存储:先利用AI模型把文本、图像、视频这些原始数据转化为向量,然后存储到向量数据库中。
  • 数据检索:进行搜索时,先把搜索的内容(文本、音频或视频)用生成原始数据向量的同一模型转化为向量,接着用这个查询向量在数据库里找到最相似的向量。向量数据库通过语义搜索,能有效解决大语言模型(LLMs)中的一些问题,比如幻觉问题。
  • 计算相似性:计算向量相似性的方法有很多,具体选择哪种方法,取决于实际应用场景和数据特点。常见的方法包括:
    • 欧氏距离:计算两个向量在欧氏空间中的直线距离。
    • 余弦相似度:通过计算两个向量夹角的余弦值来衡量相似度。
    • 曼哈顿距离(L1距离):把向量各分量的绝对差值相加得到的结果。
    • 杰卡德相似度:用两个向量交集的大小除以并集的大小来计算。

目前市面上的向量数据库有很多,像Pinecone、Elasticsearch这些来自初创公司,Chroma、Weaviate、Quadrant则属于开源数据库。

二、Spring向量存储接口

在Spring AI里,VectorStore接口是与向量数据库交互的主要接口。它提供了在向量数据库中存储Document对象的方法,以及对存储的向量进行相似性搜索的方法。代码如下:

public interface VectorStore {
    // 将文档列表添加到向量数据库
    void add(List<Document> documents); 
    // 根据文档ID列表删除文档,返回删除操作是否成功的结果
    Optional<Boolean> delete(List<String> idList); 
    // 根据查询字符串进行相似性搜索,返回最相似的文档列表
    List<Document> similaritySearch(String query); 
    // 根据搜索请求进行相似性搜索,返回最相似的文档列表
    List<Document> similaritySearch(SearchRequest request); 
}

这里的Document对象封装了原始内容、向量嵌入,以及文件名等相关元数据,具体定义如下:

public class Document implements Content {
    // 存储文档的元数据,如文件名、文件类型等
    private Map<String, Object> metadata; 
    // 文档的原始内容,比如文本文件的文本内容
    private String content; 
    // 文档对应的向量嵌入,是一个由双精度浮点数组成的列表
    private List<Double> embedding = new ArrayList<>(); 
    // 其他方法和构造函数省略
}

三、文档的存储与查询

当Spring Boot检测到项目中添加了支持向量数据库的启动器模块时,会自动初始化VectorStore类型的bean。比如,添加spring-ai-chroma-store-spring-boot-starter依赖后,Spring Boot会自动配置ChromaDB,并创建ChromaVectorStore类型的bean。我们可以通过通用的VectorStore接口来访问这个bean,这样后续如果要切换到其他向量数据库,也无需修改代码。

// 通过依赖注入获取VectorStore类型的bean
@Autowired 
VectorStore vectorStore; 

获取到VectorStore bean后,就可以用它在数据库中存储文档:

// 创建包含多个Document对象的列表,每个Document对象包含文档内容
List<Document> documents = List.of(
        new Document("...content..."),
        new Document("...content..."),
        new Document("...content...")); 
// 将文档列表添加到向量数据库
vectorStore.add(documents); 

也可以进行语义搜索:

// 根据搜索条件构建搜索请求,查询与“...search-terms...”相关的文档,并返回最相似的5个
List<Document> results = vectorStore.similaritySearch(
        SearchRequest.query("...search-terms...").withTopK(5) ); 

Spring AI支持多种向量数据库,并且未来还会增加更多支持。如需查看完整的支持数据库列表及配置,请访问官方文档。

四、SimpleVectorStore介绍

在做演示时,为了避免配置复杂的向量存储数据库,我们可以使用SimpleVectorStore。它是VectorStore接口的一个简单实现,提供了将向量当前状态保存到文件,以及从文件加载向量的方法。这有点像在开发环境中,用H2内存数据库代替常规关系型数据库。不过要注意,它不会从数据库保存或加载嵌入文件,只是提供文件操作的方法。

public class SimpleVectorStore implements VectorStore {
    // 添加文档到向量存储
    public void add(List<Document> documents) {...} 
    // 根据搜索请求进行相似性搜索
    public List<Document> similaritySearch(SearchRequest request) {...} 
    // 将向量存储的当前状态保存到指定文件
    public void save(File file) {...} 
    // 从指定文件加载向量
    public void load(File file) {...} 
    // 从指定资源加载向量
    public void load(Resource resource) {...} 
    // 其他方法省略
}

SimpleVectorStore bean只需要EmbeddingModel bean的引用,用于从原始数据生成向量嵌入。可以通过以下方式创建SimpleVectorStore bean:

// 定义一个Spring Bean,创建SimpleVectorStore实例,并传入EmbeddingModel实例
@Bean 
SimpleVectorStore vectorStore(EmbeddingModel embeddingModel) {
    return new SimpleVectorStore(embeddingModel); 
}

五、使用ChromaDB进行向量存储演示

下面通过配置Chroma数据库,并利用它存储和查询嵌入向量,来展示VectorStore bean的实际应用。

(一)设置ChromaDB

这里借助Spring Boot的Docker Compose支持来设置Chroma数据库。在项目根目录下创建docker-compose.yml文件,内容如下:

version: '3.9'

networks:
  net:
    driver: bridge
services:
  server:
    image: ghcr.io/chroma-core/chroma:latest
    environment:
      - IS_PERSISTENT=TRUE
    volumes:
      - chroma-data:/chroma/chroma/
    ports:
      - 8000:8000
    networks:
      - net

volumes:
  chroma-data:
    driver: local

这样,docker-compose模块就能启动Chroma数据库。

(二)配置Maven依赖

接着,在项目的pom.xml文件中添加相关的Maven依赖,让Spring Boot配置必要的bean:

<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-openai-spring-boot-starter</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-chroma-store-spring-boot-starter</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-docker-compose</artifactId>
    <scope>runtime</scope>
    <optional>true</optional>
</dependency>

其中,OpenAiEmbeddingModel用于从原始数据创建嵌入向量,ChromaVectorStore用于存储和查询生成的嵌入向量。spring-boot-docker-compose会扫描前面定义的docker-compose.yml文件,启动数据库实例,并自动读取数据库连接信息,创建VectorStore bean。

此外,还可以添加其他库来辅助读取、解析和分词文档,比如:

<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-tika-document-reader</artifactId>
</dependency>

(三)将数据加载到向量存储

读取原始数据并创建嵌入向量的方式因项目而异。在这个演示中,创建了VectorStoreLoader类,借助Apache Tika库读取文本文件、Markdown文件和PDF文件。代码如下:

import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import org.springframework.ai.document.Document;
import org.springframework.ai.reader.TextReader;
import org.springframework.ai.reader.tika.TikaDocumentReader;
import org.springframework.ai.transformer.splitter.TokenTextSplitter;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Component;

@Component
public class VectorStoreLoader implements ApplicationRunner {
    // 注入PDF文件资源
    @Value("classpath:/CallingRates.pdf") 
    Resource pdfResource; 
    // 注入文本文件资源
    @Value("classpath:/story.txt") 
    Resource txtResource; 
    // 注入Markdown文件资源
    @Value("classpath:/story.md") 
    Resource mdResource; 
    // 注入VectorStore实例
    @Autowired 
    VectorStore vectorStore; 

    @Override
    public void run(ApplicationArguments args) throws Exception {
        List<Document> documents = new ArrayList<>();

        // 使用TikaDocumentReader读取PDF文件内容,并添加到documents列表
        TikaDocumentReader reader = new TikaDocumentReader(pdfResource); 
        documents.addAll(reader.get()); 
        // 将documents列表添加到向量存储
        vectorStore.add(documents); 

        // 创建TextReader读取文本文件,设置字符集后读取内容并添加到documents列表
        var textReader1 = new TextReader(txtResource); 
        textReader1.setCharset(Charset.defaultCharset()); 
        documents.addAll(textReader1.get()); 

        // 创建TextReader读取Markdown文件,设置字符集后读取内容并添加到documents列表
        var textReader2 = new TextReader(mdResource); 
        textReader2.setCharset(Charset.defaultCharset()); 
        documents.addAll(textReader2.get()); 

        // 使用TokenTextSplitter对documents进行分词处理后,再添加到向量存储
        vectorStore.add(new TokenTextSplitter(300, 300, 5, 1000, true).split(documents)); 

        System.out.println("Added documents to vector store");
    }
}

这个类会把读取的数据添加到Document对象,最后存入向量存储。向量存储内部会调用嵌入模型,将生成的向量存储到数据库中。

(四)相似性搜索

需要时,调用vectorStore.similaritySearch()方法,就能找到与查询词匹配的相似文档。示例代码如下:

// 根据“investigation”进行相似性搜索,获取最相似的文档列表
List<Document> documents = vectorStore.similaritySearch("investigation"); 
// 遍历并打印搜索结果
documents.stream().forEach(System.out::println); 

程序输出结果类似:

Document{id='7cec17aa-...', metadata={source=story.md  , distance=0.7674138}, content='...', media=[]}
Document{id='42726cdb-...', metadata={source=story.text, distance=0.8732333}, content='...', media=[]}
Document{id='9aad7daa-...', metadata={source=story.pdf , distance=0.8799484}, content='...', media=[]} 

六、总结

通过这个Spring AI向量数据库的示例,我们了解了向量和向量数据库的概念,掌握了向量在数据库中的存储方式,以及如何利用相似性搜索查找相关数据。还探讨了Spring AI的VectorStore接口,以及如何借助Spring Boot自动配置创建和使用具体的实现类。最后,通过使用Docker Compose设置Chroma向量数据库,并结合OpenAI嵌入模型存储向量嵌入的示例,对整个流程有了更直观的认识。希望读者能通过本文的学习,在实际项目中灵活运用向量数据库技术。

归属教程 Spring AI 快速入门教程汇总

文章目录 Spring AI是什么?有啥优势? 如何在项目中使用Spring AI? Spring AI详细功 […]


版权声明:本站文章,如无说明,均为本站原创,转载请注明文章来源。如有侵权,请联系博主删除。
本文链接:https://www.panziye.com/back/14856.html
喜欢 (0)
请潘老师喝杯Coffee吧!】
分享 (0)
用户头像
发表我的评论
取消评论
表情 贴图 签到 代码

Hi,您需要填写昵称和邮箱!

  • 昵称【必填】
  • 邮箱【必填】
  • 网址【可选】