LangChain4j(14)——向量存储

该文章已生成可运行项目,

使用RAG时,需要对文档分段后进行存储,之前的例子中,我们是将向量数据存入内存。事实上,LangChain4j集成了20中以上的向量存储方式。

LangChain4j支持的向量存储

Embedding StoreStoring MetadataFiltering by MetadataRemoving Embeddings
In-memory
AlloyDB for Postgres
Astra DB
Azure AI Search
Azure CosmosDB Mongo vCore
Azure CosmosDB NoSQL
Cassandra
Chroma
ClickHouse
Cloud SQL for Postgres
Coherence
Couchbase
DuckDB
Elasticsearch
Infinispan
Milvus
MongoDB Atlas
Neo4j
OpenSearch
Oracle
PGVector
Pinecone
Qdrant
Redis
Tablestore
Vearch
Vespa
Weaviate

本例,我们将向量输入存入redis中。为此,我们需要安装redis stack服务。

redis-stack安装

redis-stack介绍

Redis Stack是Redis的扩展,它提供了一系列功能的扩展扩展,比如,全文搜索、文档数据库、时间序列数据、图形数据和矢量搜索等。

Redis Stack 是一组软件套件,它主要由三部分组成:

  • Redis Stack Server,由 Redis,RedisSearch,RedisJSON,RedisGraph,RedisTimeSeries 和 RedisBloom 组成
  • RedisInsight,官方提供的强大的redis客户端工具
  • Redis Stack 客户端 SDK,包括Java、JavaScript、Python

通过docker安装redis-stack

我们通过docker安装redis-stack套件,首先拉取镜像:

docker pull redis/redis-stack

拉取镜像后,运行容器:

docker run -d --name redis-stack -p 8001:8001 -p 6379:6379 -v /root/redisstack/data:/data/redis_data redis/redis-stack

其中8001端口用于访问RedisInsight。

访问RedisInsight

访问地址:http://宿主机ip:8001

向redis-stack写入向量数据

导入jar

存储向量数据,一般要求jedis使用5.2.0及以上版本。

<dependency>
  <groupId>dev.langchain4j</groupId>
  <artifactId>langchain4j-community-redis</artifactId>
  <version>1.0.0-beta2</version>
  <exclusions>
    <exclusion>
      <groupId>redis.clients</groupId>
      <artifactId>jedis</artifactId>
    </exclusion>
  </exclusions>
</dependency>

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

 测试代码

package com.renr.langchain4jnew.app4;

import dev.langchain4j.community.store.embedding.redis.RedisEmbeddingStore;
import dev.langchain4j.data.embedding.Embedding;
import dev.langchain4j.data.segment.TextSegment;
import dev.langchain4j.model.embedding.EmbeddingModel;
import dev.langchain4j.model.embedding.onnx.bgesmallzhv15.BgeSmallZhV15EmbeddingModel;
import dev.langchain4j.store.embedding.EmbeddingMatch;
import dev.langchain4j.store.embedding.EmbeddingSearchRequest;
import dev.langchain4j.store.embedding.EmbeddingStore;

import java.util.List;


public class RedisEmbeddingStoreTest {

    public static void main(String[] args) {

        // 创建redis向量存储对象
        EmbeddingStore<TextSegment> embeddingStore = RedisEmbeddingStore.builder()
                .host("localhost") // reids ip
                .port(6379) // redis 端口
                .indexName("mytest") // 索引名称,可以不写
                // .dimension(512)
                .build();
        // 创建嵌入模型对象
        EmbeddingModel embeddingModel = new BgeSmallZhV15EmbeddingModel();

        // 将指定的数据向量化,并存入redis
        TextSegment segment1 = TextSegment.from("I like football.");
        Embedding embedding1 = embeddingModel.embed(segment1).content();
        embeddingStore.add(embedding1, segment1);

        TextSegment segment2 = TextSegment.from("The weather is good today.");
        Embedding embedding2 = embeddingModel.embed(segment2).content();
        embeddingStore.add(embedding2, segment2);

        // 向需要比对的内容向量化
        Embedding queryEmbedding = embeddingModel.embed("What is your favourite sport?").content();
        // 创建搜索对象
        EmbeddingSearchRequest embeddingSearchRequest = EmbeddingSearchRequest.builder()
                .queryEmbedding(queryEmbedding)
                .maxResults(2) // 指定返回的搜索结果的最大个数
                .build();
        // 进行相似度搜索
        List<EmbeddingMatch<TextSegment>> matches = embeddingStore.search(embeddingSearchRequest).matches();
        // 获取匹配的数据
        EmbeddingMatch<TextSegment> embeddingMatch = matches.get(0);
        // 打印计算的结果
        System.out.println(embeddingMatch.score());
        System.out.println(embeddingMatch.embedded().text());

    }
}

执行结果

查看redis中数据

LangChain4j使用JSON格式存储向量数据,而且数据中包含原来的文档内容text和向量化后的数据vector。

通过查看源码,其中使用KNN算法(K-邻近算法)进行向量搜索。

RAG中使用redis作为向量存储

package com.renr.langchain4jnew.app5;

import com.renr.langchain4jnew.app4.NaiveRAG;
import com.renr.langchain4jnew.constant.CommonConstants;
import dev.langchain4j.community.model.zhipu.ZhipuAiChatModel;
import dev.langchain4j.community.store.embedding.redis.RedisEmbeddingStore;
import dev.langchain4j.data.document.Document;
import dev.langchain4j.data.document.DocumentParser;
import dev.langchain4j.data.document.loader.FileSystemDocumentLoader;
import dev.langchain4j.data.document.parser.TextDocumentParser;
import dev.langchain4j.data.document.splitter.DocumentSplitters;
import dev.langchain4j.data.segment.TextSegment;
import dev.langchain4j.memory.chat.MessageWindowChatMemory;
import dev.langchain4j.model.chat.ChatLanguageModel;
import dev.langchain4j.model.embedding.EmbeddingModel;
import dev.langchain4j.model.embedding.onnx.bgesmallzhv15.BgeSmallZhV15EmbeddingModel;
import dev.langchain4j.rag.DefaultRetrievalAugmentor;
import dev.langchain4j.rag.RetrievalAugmentor;
import dev.langchain4j.rag.content.injector.ContentInjector;
import dev.langchain4j.rag.content.injector.DefaultContentInjector;
import dev.langchain4j.rag.content.retriever.ContentRetriever;
import dev.langchain4j.rag.content.retriever.EmbeddingStoreContentRetriever;
import dev.langchain4j.service.AiServices;
import dev.langchain4j.store.embedding.EmbeddingStore;
import dev.langchain4j.store.embedding.EmbeddingStoreIngestor;

import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.Duration;

import static java.util.Arrays.asList;

public class AdvancedRAG03_RedisStore {

    public static void main(String[] args) throws URISyntaxException {
        ChatLanguageModel chatModel = ZhipuAiChatModel.builder()
                // 模型key
                .apiKey(CommonConstants.API_KEY)
                // 精确度
                .temperature(0.9)
                .model("GLM-4-Flash")
                .maxRetries(3)
                .callTimeout(Duration.ofSeconds(60))
                .connectTimeout(Duration.ofSeconds(60))
                .writeTimeout(Duration.ofSeconds(60))
                .readTimeout(Duration.ofSeconds(60))
                .logRequests(true)
                .logResponses(true)
                .build();

        // 获取待加载的文档路径
        URL fileUrl = NaiveRAG.class.getClassLoader().getResource("document/医院.txt");
        Path path = Paths.get(fileUrl.toURI());
        // 指定文档解析器
        DocumentParser documentParser = new TextDocumentParser();
        // 加载文档数据
        Document document = FileSystemDocumentLoader.loadDocument(path, documentParser);

        // 支持中文的嵌入模型
        EmbeddingModel embeddingModel = new BgeSmallZhV15EmbeddingModel();

        // 使用redis作为向量存储对象
        EmbeddingStore<TextSegment> embeddingStore = RedisEmbeddingStore.builder()
                .host("localhost") // reids ip
                .port(6379) // redis 端口
                .indexName("mytest") // 索引名称,可以不写
                // .dimension(512)
                .build();

        EmbeddingStoreIngestor ingestor = EmbeddingStoreIngestor.builder()
                .documentSplitter(DocumentSplitters.recursive(300, 0))
                // .documentSplitter(new DocumentByLineSplitter(300, 0))
                .embeddingModel(embeddingModel)
                .embeddingStore(embeddingStore)
                .build();

        ingestor.ingest(document);

        ContentRetriever contentRetriever = EmbeddingStoreContentRetriever.builder()
                .embeddingStore(embeddingStore)
                .embeddingModel(embeddingModel)
                // 每次最多检索2个最符合要求的分段
                .maxResults(2)
                // 指定检索时的最低相似度分数
                .minScore(0.5)
                .build();

        ContentInjector contentInjector = DefaultContentInjector.builder()
                // .promptTemplate(...) // Formatting can also be changed
                .metadataKeysToInclude(asList("file_name", "index"))
                .build();

        RetrievalAugmentor retrievalAugmentor = DefaultRetrievalAugmentor.builder()
                .contentRetriever(contentRetriever)
                .contentInjector(contentInjector)
                .build();


        Assistant assistant = AiServices.builder(Assistant.class)
                .chatLanguageModel(chatModel)
                .retrievalAugmentor(retrievalAugmentor)
                .chatMemory(MessageWindowChatMemory.withMaxMessages(10))
                .build();
        // String answer = assistant.chat("医院地址");
        String answer = assistant.chat("医院职工数");
        System.out.println(answer);


    }


}

执行后,查看redis中数据:

本文章已经生成可运行项目
### 如何使用LangChain4J与向量数据库集成 对于希望利用Java环境中的向量数据库功能的开发者来说,`langchain4j` 提供了一种有效的方法来连接不同的向量数据库解决方案。尽管官方文档可能更侧重于Python版本的支持,在Java端同样可以通过特定的方式完成相似的任务。 #### 安装依赖项 为了使 `langchain4j` 能够与向量数据库协同工作,首先需要确保项目包含了必要的依赖项。这通常涉及到引入相应的客户端库或者API接口,以便能够执行查询和其他操作。例如,如果打算使用类似于Epsilla这样的外部服务,则应按照其官方说明添加对应的SDK至项目的构建文件中[^2]。 ```xml <!-- Maven pom.xml --> <dependency> <groupId>com.example</groupId> <artifactId>epsilla-client</artifactId> <version>1.0.0</version> </dependency> ``` #### 初始化配置 接下来就是初始化阶段,这里会涉及创建一个指向目标向量数据库实例的对象,并对其进行适当配置。具体做法取决于所选的技术栈;比如当选用的是基于PostgreSQL扩展而来的 PGVector 时,就需要通过 JDBC 连接字符串指定主机地址、端口以及认证信息等参数[^1]: ```java // Java代码片段:建立到PGVector的数据源链接 DataSource dataSource = new JdbcDataSource(); ((JdbcDataSource)dataSource).setUrl("jdbc:postgresql://localhost:5432/mydb"); ((JdbcDataSource)dataSource)..setUser("user"); ((JdbcDataSource)dataSource).setPassword("password"); PgVector vectorDB = PgVector.builder().withDataSource(dataSource).build(); ``` #### 执行基本操作 一旦完成了上述准备工作之后就可以开始编写业务逻辑了——即如何把待处理的信息转化为适合存储的形式(通常是浮点数数组),再调用相应方法将其保存起来或是发起查找请求。下面给出一段简单的演示程序,展示了怎样往已有的表里插入新记录并随后读取最接近给定特征值的结果集: ```java // 插入新的向量条目 vectorDB.addVectors(Arrays.asList( Vector.newBuilder() .setId(1L) .setData(new float[]{...}) .build())); // 查询最近邻 List<VectorSearchResult> results = vectorDB.findNearestNeighbors( new float[]{...}, // 待比较的目标向量 5 // 返回前几名匹配度最高的对象 ); for (var result : results){ System.out.println(result.getId() + ": " + result.getScore()); } ``` 以上便是关于如何借助 `langchain4j` 实现同各类向量型数据管理系统对接的一个概览介绍。值得注意的是实际应用场景下往往还需要考虑更多细节方面的要求,如性能优化策略的选择、错误恢复机制的设计等等。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值