Spring Boot AI使用Redis Vector Database作为向量数据库

deepseek > AI (32) 2025-02-20 17:41:04

目标

使用Redis Stack中间件作为向量数据库(Vector Database)实现文档数据的存储和查询功能。

先决条件

已安装好的 redis stack ,redis stack 安装可参考:redis-stack 安装(Docker)

增加redis stock部分maven依赖

该项目基于Spring Boot 接入Ollama实现与Deepseek简单对话修改

<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-redis-store-spring-boot-starter</artifactId>
</dependency>

application.yml增加redis相关配置

spring:
  application:
    name: demo-boot-ollama
  ai:
    vectorstore:
      redis:
        initialize-schema: true
        prefix: custom-prefix
        index: custom-index
    ollama: # ai 提供者 ollama
      init:
        pull-model-strategy: never # 下载策略
        embedding:
          additional-models:
            - mxbai-embed-large #redis 向量库默认嵌入模型必须存在否则报错
            - nomic-embed-text
            - chroma/all-minilm-l6-v2-f32
      base-url: http://192.168.31.162:11434
      chat:
        options:
          model: deepseek-r1:8b
  data:
    redis:
      host: 192.168.31.162

Redis Vector Database 写入/查询测试示例

@SpringBootTest
public class RedisVectorTests {
   @Resource
   VectorStore vectorStore;
   @Test
   public void saveDocumentsAndQuery() {
       List<Document> documents = List.of(
               new Document("Spring AI rocks!! Spring AI rocks!! Spring AI rocks!! Spring AI rocks!! Spring AI rocks!!", Map.of("meta1", "meta1")),
               new Document("The World is Big and Salvation Lurks Around the Corner"),
               new Document("You walk forward facing the past and you turn back toward the future.", Map.of("meta2", "meta2")));
       // 文档添加到redis
       vectorStore.add(documents);
      // 检索文档类似于查询
       List<Document> results = this.vectorStore.similaritySearch(SearchRequest.builder().query("Spring").topK(5).build());
   }
}

执行结果

Spring Boot AI使用Redis Vector Database作为向量数据库_图示-1cb9ba8e4a664a1a9a4643a978cf43ee.png
第一次执行
Spring Boot AI使用Redis Vector Database作为向量数据库_图示-19fc9bbc0b6745ae9994f6f1d7497bff.png
第二次执行

提示:第二次执行,由于重复写入了两次所以数据有两份,但是查询结果确实根据相关度分数来的,且一共6个数据只查询了分数高的5个

Redis 数据查看:

Spring Boot AI使用Redis Vector Database作为向量数据库_图示-9559bacdc1444c3a9661fe22f4d2d425.png
Redis 数据查看

向量数据库数据存储流程解析

Spring Boot AI使用Redis Vector Database作为向量数据库_图示-c7c7574e44424ddfa732b8a1554d5d97.png
向量数据转换+存储大致流程

通过源码可以看到在存入redis之前,对数据进行了大模型嵌入化,使用了mxbai-embed-large模型

Spring Boot AI使用Redis Vector Database作为向量数据库_图示-752019932c964f819e42af3712fa59c6.png
源码断点调试

 

自定义向量数据库嵌入解析模型

自定义RedisVectorStore, 添加以下配置文件:

@Configuration
public class CustomVectorEmbeddingModelConfig {
    @Bean
    public EmbeddingModel embeddingModel(OllamaApi ollamaApi) {
        return new OllamaEmbeddingModel(
                ollamaApi,
                OllamaOptions.builder()
                        .model(OllamaModel.NOMIC_EMBED_TEXT.id()) //自定义嵌入模型 nomic-embed-text
                        .build(),
                ObservationRegistry.NOOP,
                ModelManagementOptions.defaults()
        );
    }
}

参考:org.springframework.ai.autoconfigure.vectorstore.redis.RedisVectorStoreAutoConfiguration 中配置

Spring Boot AI使用Redis Vector Database作为向量数据库_图示-afc38134b8774a81941a703369d1c03b.png
org.springframework.ai.autoconfigure.vectorstore.redis.RedisVectorStoreAutoConfiguration

可知,嵌入模型是通过外部已有的bean传递进来的,所以如果只是切换模型就直接重写EmbeddingModel实现即可,参考上方。

 

启动之后断点查看

Spring Boot AI使用Redis Vector Database作为向量数据库_图示-f9f58e7423e04e80ba2ba2f583adf8d9.png
嵌入量化模型已修改为自定义的:nomic-embed-text

注意:修改模型会导致已有数据不兼容!!!

自定义之后就可以继续玩复杂查询了

重写自定义RedisVectorStore(目前版本好像没有其他方法配置增加metadata过滤字段让查询时候生效),添加过滤metadata过滤字段

@Bean
public RedisVectorStore vectorStore(EmbeddingModel embeddingModel, RedisVectorStoreProperties properties, JedisConnectionFactory jedisConnectionFactory, ObjectProvider<ObservationRegistry> observationRegistry, ObjectProvider<VectorStoreObservationConvention> customObservationConvention, BatchingStrategy batchingStrategy) {
    JedisPooled jedisPooled = this.jedisPooled(jedisConnectionFactory);
    return ((RedisVectorStore.Builder)((RedisVectorStore.Builder)((RedisVectorStore.Builder)RedisVectorStore.builder(jedisPooled, embeddingModel)
            .metadataFields(//定义 metadata 用于过滤(filtering)的数据字段
                    RedisVectorStore.MetadataField.tag("m1"),
                    RedisVectorStore.MetadataField.tag("m2")
            )
            .initializeSchema(properties.isInitializeSchema()).observationRegistry((ObservationRegistry)observationRegistry.getIfUnique(() -> {
        return ObservationRegistry.NOOP;
    }))).customObservationConvention((VectorStoreObservationConvention)customObservationConvention.getIfAvailable(() -> {
        return null;
    }))).batchingStrategy(batchingStrategy)).indexName(properties.getIndex()).prefix(properties.getPrefix()).build();
}
private JedisPooled jedisPooled(JedisConnectionFactory jedisConnectionFactory) {
    String host = jedisConnectionFactory.getHostName();
    int port = jedisConnectionFactory.getPort();
    JedisClientConfig clientConfig = DefaultJedisClientConfig.builder().ssl(jedisConnectionFactory.isUseSsl()).clientName(jedisConnectionFactory.getClientName()).timeoutMillis(jedisConnectionFactory.getTimeout()).password(jedisConnectionFactory.getPassword()).build();
    return new JedisPooled(new HostAndPort(host, port), clientConfig);
}

重点代码:



...其他忽略...
        return ((RedisVectorStore.Builder)((RedisVectorStore.Builder)((RedisVectorStore.Builder)
        RedisVectorStore.builder(jedisPooled, embeddingModel)
                .metadataFields(//定义 metadata 用于过滤(filtering)的数据字段
                        RedisVectorStore.MetadataField.tag("m1"),
                        RedisVectorStore.MetadataField.tag("m2")
                )
...其他忽略...

其余代码参考:org.springframework.ai.autoconfigure.vectorstore.redis.RedisVectorStoreAutoConfiguration

 

生成新数据:

List<Document> documents = List.of(
        new Document("Spring AI rocks!! Spring AI rocks!! Spring AI rocks!! Spring AI rocks!! Spring AI rocks!!", Map.of("m2", "meta1")),
        new Document("The World is Big and Salvation Lurks Around the Corner"),
        new Document("You walk forward facing the past and you turn back toward the future.", Map.of("m1", "meta2")));

metadata 过滤查询:

        List<Document> result = redisVectorStore.similaritySearch(
                SearchRequest.builder()
                .query("Spring")
                .topK(5)
                .similarityThreshold(SearchRequest.SIMILARITY_THRESHOLD_ACCEPT_ALL)
                .filterExpression(
//                        "m2 in ['meta1'] || m1 in ['meta2']"
                        b.or(
                        b.in("m2", "meta1"),
                        b.in("m1","meta2")
                        ).build()
                ).build());

执行结果:

Spring Boot AI使用Redis Vector Database作为向量数据库_图示-23ded4ce9b964a9e801085f3a93fd245.png
2个记录

 

注意哈:虽然只匹配到了一个metadata但是评分高0.7***。评分和算法有关。

 

更多玩法:


评论
User Image
提示:请评论与当前内容相关的回复,广告、推广或无关内容将被删除。

相关文章
目标使用Redis Stack中间件作为向量数据库(Vector Database)实现文档数据的存储和查询功能。先决条件已安装好的 redis stack ,
前置条件Docker 环境开始安装redis-stack打开docker官方hub的地址 redis/redis-stack Tags | Docker Hub
概述本文讲解Java编程中如何通过Spring AI框架 集成 Redis Stack 向量数据库和Ollama模型服务提供者实现RAG本地外挂知识库。前置条件
Spring Boot 2.0 Redis整合,通过spring boot 2.0整合Redis作为spring缓存框架的实现。
spring boot 1.5整合redis实现spring的缓存框架,spring boot,redis
redis 命令查看使用情况redis info命令详解,redis查看内存使用情况。redis info命令的详细解释
Redis 删除/清除数据​​​​​​​1.访问redis根目录    cd  /usr/local/redis-2.8.192.登录redis:redis-cli -h 127.0.0.1 -...
Redis 禁用持久化配置
spring data redis设置缓存的过期时间,spring data redis更新缓存的过期时间
简述本文主要通过一个简单的例子模拟实现秒杀情景,其中主要使用Redis事物进行实现spring boot为提供方便的环境
Java连接redis启动报错Error redis clients jedis HostAndPort cant resolve localhost address
今天遇到Redis “MISCONF Redis is configured to save RDB snapshots, but is currently not able to persis...
redis在window系统上的下载安装使用说明
简述在本博客中,我们将会创建一个reids的消息队列,Redis可以被当成消息队列使用
Docker安装部署Redisdocker 安装部署Redis环境Linux系统dockerdocker-compose 相关文章:Ubuntu 在线安装 Docker-xqlee (blog....