Lzh on GitHub

Redis

本节将引导你设置 RedisVectorStore,用于存储文档向量(embeddings)并执行相似性搜索。

本节将引导你设置 RedisVectorStore,用于存储文档向量(embeddings)并执行相似性搜索。

Redis 是一个开源(BSD 许可)的内存数据结构存储,可用作数据库、缓存、消息代理和流处理引擎。Redis 提供的数据结构包括字符串(strings)、哈希(hashes)、列表(lists)、集合(sets)、带范围查询的有序集合(sorted sets)、位图(bitmaps)、HyperLogLogs、地理空间索引(geospatial indexes)以及流(streams)。

Redis Search 和 Query 扩展了 Redis OSS 的核心功能,使你可以将 Redis 用作向量数据库:

  • 在哈希或 JSON 文档中存储向量及其相关元数据
  • 检索向量
  • 执行向量搜索

前置条件

  1. 一个 Redis Stack 实例:
  2. 需要一个 EmbeddingModel 实例来计算文档向量(embeddings),有多种选项可供选择:
    • 如果需要,还需为 EmbeddingModel 提供 API Key,用于生成存储在 RedisVectorStore 中的向量嵌入。

自动配置

Spring AI 的自动配置和 starter 模块的 artifact 名称发生了重大变化,请参考升级说明了解更多信息。

Spring AI 为 Redis 向量存储提供了 Spring Boot 自动配置。要启用它,请在项目的 Maven pom.xml 文件中添加以下依赖:

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

或者在 Gradle 的 build.gradle 文件中添加:

dependencies {
    implementation 'org.springframework.ai:spring-ai-starter-vector-store-redis'
}
请参考 依赖管理 部分,将 Spring AI BOM 添加到你的构建文件中。
请参考 artifact 仓库 部分,将 Maven Central 和/或 Snapshot 仓库添加到构建文件中。

向量存储实现可以为你初始化所需的 schema,但你必须显式选择启用,通过在相应构造函数中指定 initializeSchema 布尔值,或在 application.properties 文件中设置:

spring.ai.vectorstore.redis.initialize-schema=true
这是一个破坏性变更!在早期版本的 Spring AI 中,这个 schema 初始化是默认启用的。

请查看向量存储的 配置参数 列表,了解默认值及其他配置选项。

此外,你还需要配置一个 EmbeddingModel Bean,具体信息请参考 EmbeddingModel 章节。

现在,你可以在应用中自动注入 RedisVectorStore 并使用它:

@Autowired
VectorStore vectorStore;

// ...

List<Document> documents = List.of(
    new Document("Spring AI 很棒!!Spring AI 很棒!!Spring AI 很棒!!Spring AI 很棒!!Spring AI 很棒!!", Map.of("meta1", "meta1")),
    new Document("世界很大,救赎就在拐角处"),
    new Document("你向前走面向过去,同时回望未来", Map.of("meta2", "meta2"))
);

// 将文档添加到 Redis
vectorStore.add(documents);

// 根据查询检索相似文档
List<Document> results = vectorStore.similaritySearch(
    SearchRequest.builder().query("Spring").topK(5).build()
);

配置属性

要连接 Redis 并使用 RedisVectorStore,你需要提供实例的访问信息。可以通过 Spring Boot 的 application.yml 提供简单配置:

spring:
  data:
    redis:
      url: <redis 实例 URL>
  ai:
    vectorstore:
      redis:
        initialize-schema: true
        index-name: custom-index
        prefix: custom-prefix

对于 Redis 连接配置,也可以通过 Spring Boot 的 application.properties 提供简单配置:

spring.data.redis.host=localhost
spring.data.redis.port=6379
spring.data.redis.username=default
spring.data.redis.password=

spring.ai.vectorstore.redis.* 开头的属性用于配置 RedisVectorStore

属性描述默认值
spring.ai.vectorstore.redis.initialize-schema是否初始化所需的 schemafalse
spring.ai.vectorstore.redis.index-name用于存储向量的索引名称spring-ai-index
spring.ai.vectorstore.redis.prefixRedis 键的前缀embedding:

元数据过滤

你也可以在 Redis 中使用通用、可移植的 元数据过滤器

例如,你可以使用文本表达式语言:

vectorStore.similaritySearch(
    SearchRequest.builder()
        .query("The World")
        .topK(TOP_K)
        .similarityThreshold(SIMILARITY_THRESHOLD)
        .filterExpression("country in ['UK', 'NL'] && year >= 2020")
        .build()
);

或者通过编程方式使用 Filter.Expression DSL:

FilterExpressionBuilder b = new FilterExpressionBuilder();

vectorStore.similaritySearch(
    SearchRequest.builder()
        .query("The World")
        .topK(TOP_K)
        .similarityThreshold(SIMILARITY_THRESHOLD)
        .filterExpression(
            b.and(
                b.in("country", "UK", "NL"),
                b.gte("year", 2020)
            ).build()
        )
        .build()
);
这些(可移植的)过滤表达式会自动转换为 Redis 专有的 搜索查询

例如,这个可移植过滤表达式:

country in ['UK', 'NL'] && year >= 2020

会被转换为 Redis 专有格式:

@country:{UK | NL} @year:[2020 inf]

手动配置

你可以选择不使用 Spring Boot 自动配置,而是手动配置 Redis 向量存储。为此,你需要将 spring-ai-redis-store 添加到项目中:

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

或者在 Gradle 的 build.gradle 文件中添加:

dependencies {
    implementation 'org.springframework.ai:spring-ai-redis-store'
}

创建一个 JedisPooled Bean:

@Bean
public JedisPooled jedisPooled() {
    return new JedisPooled("<host>", 6379);
}

然后使用构建者模式(builder pattern)创建 RedisVectorStore Bean:

@Bean
public VectorStore vectorStore(JedisPooled jedisPooled, EmbeddingModel embeddingModel) {
    return RedisVectorStore.builder(jedisPooled, embeddingModel)
        .indexName("custom-index")                // 可选,默认: "spring-ai-index"
        .prefix("custom-prefix")                  // 可选,默认: "embedding:"
        .metadataFields(                          // 可选,为过滤器定义元数据字段
            MetadataField.tag("country"),
            MetadataField.numeric("year"))
        .initializeSchema(true)                   // 可选,默认: false
        .batchingStrategy(new TokenCountBatchingStrategy()) // 可选,默认: TokenCountBatchingStrategy
        .build();
}

// 这里可以使用任何 EmbeddingModel 实现
@Bean
public EmbeddingModel embeddingModel() {
    return new OpenAiEmbeddingModel(new OpenAiApi(System.getenv("OPENAI_API_KEY")));
}
注意:你必须显式列出在过滤表达式中使用的所有元数据字段名称及其类型(TAGTEXTNUMERIC)。上例中的 metadataFields 注册了可用于过滤的元数据字段:
  • country 类型为 TAG
  • year 类型为 NUMERIC

访问原生客户端

Redis 向量存储实现通过 getNativeClient() 方法提供对底层原生 Redis 客户端(JedisPooled)的访问:

RedisVectorStore vectorStore = context.getBean(RedisVectorStore.class);
Optional<JedisPooled> nativeClient = vectorStore.getNativeClient();

if (nativeClient.isPresent()) {
    JedisPooled jedis = nativeClient.get();
    // 使用原生客户端执行 Redis 特定操作
}

原生客户端让你可以访问 VectorStore 接口未暴露的 Redis 特定功能和操作。