diff --git a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-redis/src/main/java/org/springframework/ai/vectorstore/redis/autoconfigure/RedisVectorStoreAutoConfiguration.java b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-redis/src/main/java/org/springframework/ai/vectorstore/redis/autoconfigure/RedisVectorStoreAutoConfiguration.java index 7d37f78d53..b7aa5b1b31 100644 --- a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-redis/src/main/java/org/springframework/ai/vectorstore/redis/autoconfigure/RedisVectorStoreAutoConfiguration.java +++ b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-redis/src/main/java/org/springframework/ai/vectorstore/redis/autoconfigure/RedisVectorStoreAutoConfiguration.java @@ -16,6 +16,8 @@ package org.springframework.ai.vectorstore.redis.autoconfigure; +import java.util.List; + import io.micrometer.observation.ObservationRegistry; import redis.clients.jedis.DefaultJedisClientConfig; import redis.clients.jedis.JedisClientConfig; @@ -70,6 +72,7 @@ BatchingStrategy batchingStrategy() { * @param jedisConnectionFactory the Jedis connection factory * @param observationRegistry the observation registry * @param convention the custom observation convention + * @param metadataFields the custom metadata fields * @param batchingStrategy the batching strategy * @return the configured Redis vector store */ @@ -79,6 +82,7 @@ public RedisVectorStore vectorStore(final EmbeddingModel embeddingModel, final RedisVectorStoreProperties properties, final JedisConnectionFactory jedisConnectionFactory, final ObjectProvider observationRegistry, final ObjectProvider convention, + final ObjectProvider> metadataFields, final BatchingStrategy batchingStrategy) { RedisClient jedisClient = jedisClient(jedisConnectionFactory); @@ -88,7 +92,8 @@ public RedisVectorStore vectorStore(final EmbeddingModel embeddingModel, .customObservationConvention(convention.getIfAvailable()) .batchingStrategy(batchingStrategy) .indexName(properties.getIndexName()) - .prefix(properties.getPrefix()); + .prefix(properties.getPrefix()) + .metadataFields(metadataFields.getIfAvailable(List::of)); // Configure HNSW parameters if available hnswConfiguration(builder, properties); diff --git a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-redis/src/test/java/org/springframework/ai/vectorstore/redis/autoconfigure/RedisVectorStoreAutoConfigurationIT.java b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-redis/src/test/java/org/springframework/ai/vectorstore/redis/autoconfigure/RedisVectorStoreAutoConfigurationIT.java index ed36171b8d..22ab09b4b4 100644 --- a/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-redis/src/test/java/org/springframework/ai/vectorstore/redis/autoconfigure/RedisVectorStoreAutoConfigurationIT.java +++ b/auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-redis/src/test/java/org/springframework/ai/vectorstore/redis/autoconfigure/RedisVectorStoreAutoConfigurationIT.java @@ -139,6 +139,24 @@ public void autoConfigurationEnabledWhenTypeIsRedis() { }); } + @Test + void customMetadataFieldsAreApplied() { + this.contextRunner.withUserConfiguration(MetadataFieldsConfig.class) + .withPropertyValues("spring.ai.vectorstore.redis.index-name=metadata-fields-index") + .run(context -> { + VectorStore vectorStore = context.getBean(VectorStore.class); + Document document = new Document("Custom metadata", Map.of("conversationId", "conversation-1")); + + vectorStore.add(List.of(document)); + + List results = vectorStore.similaritySearch(SearchRequest.builder() + .query("metadata") + .filterExpression("conversationId == 'conversation-1'") + .build()); + assertThat(results).extracting(Document::getId).contains(document.getId()); + }); + } + @Configuration(proxyBeanMethods = false) static class Config { @@ -154,4 +172,14 @@ public EmbeddingModel embeddingModel() { } + @Configuration(proxyBeanMethods = false) + static class MetadataFieldsConfig { + + @Bean + List metadataFields() { + return List.of(RedisVectorStore.MetadataField.tag("conversationId")); + } + + } + } diff --git a/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/vectordbs/redis.adoc b/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/vectordbs/redis.adoc index a3eda81407..791d4efbb4 100644 --- a/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/vectordbs/redis.adoc +++ b/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/vectordbs/redis.adoc @@ -82,6 +82,16 @@ vectorStore.add(documents); List results = this.vectorStore.similaritySearch(SearchRequest.builder().query("Spring").topK(5).build()); ---- +To include custom metadata fields in the auto-configured Redis schema, define a `List` bean: + +[source,java] +---- +@Bean +List redisMetadataFields() { + return List.of(RedisVectorStore.MetadataField.tag("conversationId")); +} +---- + [[redisvector-properties]] === Configuration Properties