Conditionally enable invidividual vector store implementations

- Introduce top level properties to support conditional logic
- The properties will have the format like "spring.ai.vectorstore.type=<vectorstore provider>" to enable specific vectore store implementation
- By default, these will be enabled when no specific properties are set. To disable, set any value other than the provider name for example, none"

Signed-off-by: Soby Chacko <soby.chacko@broadcom.com>
This commit is contained in:
Soby Chacko
2025-03-13 20:58:33 -04:00
committed by Mark Pollack
parent 6b12ff5ae1
commit 8a1dcfc225
38 changed files with 661 additions and 3 deletions

View File

@@ -23,12 +23,14 @@ import io.micrometer.observation.ObservationRegistry;
import org.springframework.ai.embedding.BatchingStrategy;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.embedding.TokenCountBatchingStrategy;
import org.springframework.ai.vectorstore.SpringAIVectorStoreTypes;
import org.springframework.ai.vectorstore.cosmosdb.CosmosDBVectorStore;
import org.springframework.ai.vectorstore.observation.VectorStoreObservationConvention;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import java.util.List;
@@ -43,6 +45,8 @@ import java.util.List;
@AutoConfiguration
@ConditionalOnClass({ CosmosDBVectorStore.class, EmbeddingModel.class, CosmosAsyncClient.class })
@EnableConfigurationProperties(CosmosDBVectorStoreProperties.class)
@ConditionalOnProperty(name = SpringAIVectorStoreTypes.TYPE, havingValue = SpringAIVectorStoreTypes.AZURE_COSMOS_DB,
matchIfMissing = true)
public class CosmosDBVectorStoreAutoConfiguration {
String endpoint;

View File

@@ -31,6 +31,7 @@ import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.transformers.TransformersEmbeddingModel;
import org.springframework.ai.vectorstore.SearchRequest;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.ai.vectorstore.cosmosdb.CosmosDBVectorStore;
import org.springframework.ai.vectorstore.filter.FilterExpressionBuilder;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
@@ -169,6 +170,33 @@ public class CosmosDBVectorStoreAutoConfigurationIT {
assertThat(results4).isEmpty();
}
@Test
public void autoConfigurationDisabledWhenTypeIsNone() {
this.contextRunner.withPropertyValues("spring.ai.vectorstore.type=none").run(context -> {
assertThat(context.getBeansOfType(CosmosDBVectorStoreProperties.class)).isEmpty();
assertThat(context.getBeansOfType(CosmosDBVectorStore.class)).isEmpty();
assertThat(context.getBeansOfType(VectorStore.class)).isEmpty();
});
}
@Test
public void autoConfigurationEnabledByDefault() {
this.contextRunner.run(context -> {
assertThat(context.getBeansOfType(CosmosDBVectorStoreProperties.class)).isNotEmpty();
assertThat(context.getBeansOfType(VectorStore.class)).isNotEmpty();
assertThat(context.getBean(VectorStore.class)).isInstanceOf(CosmosDBVectorStore.class);
});
}
@Test
public void autoConfigurationEnabledWhenTypeIsAzureCosmosDB() {
this.contextRunner.withPropertyValues("spring.ai.vectorstore.type=azure-cosmmos-db").run(context -> {
assertThat(context.getBeansOfType(CosmosDBVectorStoreProperties.class)).isNotEmpty();
assertThat(context.getBeansOfType(VectorStore.class)).isNotEmpty();
assertThat(context.getBean(VectorStore.class)).isInstanceOf(CosmosDBVectorStore.class);
});
}
@Configuration(proxyBeanMethods = false)
static class Config {

View File

@@ -28,6 +28,7 @@ import io.micrometer.observation.ObservationRegistry;
import org.springframework.ai.embedding.BatchingStrategy;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.embedding.TokenCountBatchingStrategy;
import org.springframework.ai.vectorstore.SpringAIVectorStoreTypes;
import org.springframework.ai.vectorstore.azure.AzureVectorStore;
import org.springframework.ai.vectorstore.observation.VectorStoreObservationConvention;
import org.springframework.beans.factory.ObjectProvider;
@@ -47,7 +48,8 @@ import org.springframework.context.annotation.Bean;
@AutoConfiguration
@ConditionalOnClass({ EmbeddingModel.class, SearchIndexClient.class, AzureVectorStore.class })
@EnableConfigurationProperties({ AzureVectorStoreProperties.class })
@ConditionalOnProperty(prefix = "spring.ai.vectorstore.azure", value = { "url", "api-key", "index-name" })
@ConditionalOnProperty(name = SpringAIVectorStoreTypes.TYPE, havingValue = SpringAIVectorStoreTypes.AZURE,
matchIfMissing = true)
public class AzureVectorStoreAutoConfiguration {
private static final String APPLICATION_ID = "spring-ai";

View File

@@ -146,6 +146,33 @@ public class AzureVectorStoreAutoConfigurationIT {
});
}
@Test
public void autoConfigurationDisabledWhenTypeIsNone() {
this.contextRunner.withPropertyValues("spring.ai.vectorstore.type=none").run(context -> {
assertThat(context.getBeansOfType(AzureVectorStoreProperties.class)).isEmpty();
assertThat(context.getBeansOfType(AzureVectorStore.class)).isEmpty();
assertThat(context.getBeansOfType(VectorStore.class)).isEmpty();
});
}
@Test
public void autoConfigurationEnabledByDefault() {
this.contextRunner.run(context -> {
assertThat(context.getBeansOfType(AzureVectorStoreProperties.class)).isNotEmpty();
assertThat(context.getBeansOfType(VectorStore.class)).isNotEmpty();
assertThat(context.getBean(VectorStore.class)).isInstanceOf(AzureVectorStore.class);
});
}
@Test
public void autoConfigurationEnabledWhenTypeIsAzure() {
this.contextRunner.withPropertyValues("spring.ai.vectorstore.type=azure").run(context -> {
assertThat(context.getBeansOfType(AzureVectorStoreProperties.class)).isNotEmpty();
assertThat(context.getBeansOfType(VectorStore.class)).isNotEmpty();
assertThat(context.getBean(VectorStore.class)).isInstanceOf(AzureVectorStore.class);
});
}
@Configuration(proxyBeanMethods = false)
static class Config {

View File

@@ -25,6 +25,7 @@ import io.micrometer.observation.ObservationRegistry;
import org.springframework.ai.embedding.BatchingStrategy;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.embedding.TokenCountBatchingStrategy;
import org.springframework.ai.vectorstore.SpringAIVectorStoreTypes;
import org.springframework.ai.vectorstore.cassandra.CassandraVectorStore;
import org.springframework.ai.vectorstore.observation.VectorStoreObservationConvention;
import org.springframework.beans.factory.ObjectProvider;
@@ -33,6 +34,7 @@ import org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfigurati
import org.springframework.boot.autoconfigure.cassandra.DriverConfigLoaderBuilderCustomizer;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
@@ -47,6 +49,8 @@ import org.springframework.context.annotation.Bean;
@AutoConfiguration(after = CassandraAutoConfiguration.class)
@ConditionalOnClass({ CassandraVectorStore.class, CqlSession.class })
@EnableConfigurationProperties(CassandraVectorStoreProperties.class)
@ConditionalOnProperty(name = SpringAIVectorStoreTypes.TYPE, havingValue = SpringAIVectorStoreTypes.CASSANDRA,
matchIfMissing = true)
public class CassandraVectorStoreAutoConfiguration {
@Bean

View File

@@ -20,6 +20,7 @@ import java.util.List;
import java.util.Map;
import io.micrometer.observation.tck.TestObservationRegistry;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.testcontainers.containers.CassandraContainer;
import org.testcontainers.junit.jupiter.Container;
@@ -34,6 +35,7 @@ import org.springframework.ai.test.vectorstore.ObservationTestUtil;
import org.springframework.ai.transformers.TransformersEmbeddingModel;
import org.springframework.ai.vectorstore.SearchRequest;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.ai.vectorstore.cassandra.CassandraVectorStore;
import org.springframework.ai.vectorstore.observation.VectorStoreObservationContext;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration;
@@ -111,6 +113,42 @@ class CassandraVectorStoreAutoConfigurationIT {
});
}
@Test
public void autoConfigurationDisabledWhenTypeIsNone() {
this.contextRunner.withPropertyValues("spring.ai.vectorstore.type=none").run(context -> {
assertThat(context.getBeansOfType(CassandraVectorStoreProperties.class)).isEmpty();
assertThat(context.getBeansOfType(CassandraVectorStore.class)).isEmpty();
assertThat(context.getBeansOfType(VectorStore.class)).isEmpty();
});
}
@Test
public void autoConfigurationEnabledByDefault() {
this.contextRunner.withPropertyValues("spring.cassandra.contactPoints=" + getContactPointHost())
.withPropertyValues("spring.cassandra.port=" + getContactPointPort())
.withPropertyValues("spring.cassandra.localDatacenter=" + cassandraContainer.getLocalDatacenter())
.withPropertyValues("spring.ai.vectorstore.cassandra.fixedThreadPoolExecutorSize=8")
.run(context -> {
assertThat(context.getBeansOfType(CassandraVectorStoreProperties.class)).isNotEmpty();
assertThat(context.getBeansOfType(VectorStore.class)).isNotEmpty();
assertThat(context.getBean(VectorStore.class)).isInstanceOf(CassandraVectorStore.class);
});
}
@Test
public void autoConfigurationEnabledWhenTypeIsCassandra() {
this.contextRunner.withPropertyValues("spring.ai.vectorstore.type=cassandra")
.withPropertyValues("spring.cassandra.contactPoints=" + getContactPointHost())
.withPropertyValues("spring.cassandra.port=" + getContactPointPort())
.withPropertyValues("spring.cassandra.localDatacenter=" + cassandraContainer.getLocalDatacenter())
.withPropertyValues("spring.ai.vectorstore.cassandra.fixedThreadPoolExecutorSize=8")
.run(context -> {
assertThat(context.getBeansOfType(CassandraVectorStoreProperties.class)).isNotEmpty();
assertThat(context.getBeansOfType(VectorStore.class)).isNotEmpty();
assertThat(context.getBean(VectorStore.class)).isInstanceOf(CassandraVectorStore.class);
});
}
private String getContactPointHost() {
return cassandraContainer.getContactPoint().getHostString();
}

View File

@@ -24,11 +24,13 @@ import org.springframework.ai.embedding.BatchingStrategy;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.embedding.TokenCountBatchingStrategy;
import org.springframework.ai.chroma.vectorstore.ChromaVectorStore;
import org.springframework.ai.vectorstore.SpringAIVectorStoreTypes;
import org.springframework.ai.vectorstore.observation.VectorStoreObservationConvention;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.util.StringUtils;
@@ -45,6 +47,8 @@ import org.springframework.web.client.RestClient;
@AutoConfiguration
@ConditionalOnClass({ EmbeddingModel.class, RestClient.class, ChromaVectorStore.class, ObjectMapper.class })
@EnableConfigurationProperties({ ChromaApiProperties.class, ChromaVectorStoreProperties.class })
@ConditionalOnProperty(name = SpringAIVectorStoreTypes.TYPE, havingValue = SpringAIVectorStoreTypes.CHROMA,
matchIfMissing = true)
public class ChromaVectorStoreAutoConfiguration {
@Bean

View File

@@ -28,6 +28,7 @@ import org.testcontainers.chromadb.ChromaDBContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import org.springframework.ai.chroma.vectorstore.ChromaVectorStore;
import org.springframework.ai.document.Document;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.observation.conventions.VectorStoreProvider;
@@ -145,6 +146,38 @@ public class ChromaVectorStoreAutoConfigurationIT {
"Collection TestCollection doesn't exist and won't be created as the initializeSchema is set to false."));
}
@Test
public void autoConfigurationDisabledWhenTypeIsNone() {
this.contextRunner.withPropertyValues("spring.ai.vectorstore.type=none").run(context -> {
assertThat(context.getBeansOfType(ChromaVectorStoreProperties.class)).isEmpty();
assertThat(context.getBeansOfType(ChromaVectorStore.class)).isEmpty();
assertThat(context.getBeansOfType(VectorStore.class)).isEmpty();
});
}
@Test
@Disabled
public void autoConfigurationEnabledByDefault() {
this.contextRunner.withPropertyValues("spring.ai.vectorstore.chroma.initializeSchema=true").run(context -> {
assertThat(context.getBeansOfType(ChromaVectorStoreProperties.class)).isNotEmpty();
assertThat(context.getBeansOfType(VectorStore.class)).isNotEmpty();
assertThat(context.getBean(VectorStore.class)).isInstanceOf(ChromaVectorStore.class);
});
}
@Test
@Disabled
public void autoConfigurationEnabledWhenTypeIsChroma() {
this.contextRunner
.withPropertyValues("spring.ai.vectorstore.type=chroma",
"spring.ai.vectorstore.chroma.initializeSchema=true")
.run(context -> {
assertThat(context.getBeansOfType(ChromaVectorStoreProperties.class)).isNotEmpty();
assertThat(context.getBeansOfType(VectorStore.class)).isNotEmpty();
assertThat(context.getBean(VectorStore.class)).isInstanceOf(ChromaVectorStore.class);
});
}
@Configuration(proxyBeanMethods = false)
static class Config {

View File

@@ -22,6 +22,7 @@ import org.elasticsearch.client.RestClient;
import org.springframework.ai.embedding.BatchingStrategy;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.embedding.TokenCountBatchingStrategy;
import org.springframework.ai.vectorstore.SpringAIVectorStoreTypes;
import org.springframework.ai.vectorstore.elasticsearch.ElasticsearchVectorStore;
import org.springframework.ai.vectorstore.elasticsearch.ElasticsearchVectorStoreOptions;
import org.springframework.ai.vectorstore.observation.VectorStoreObservationConvention;
@@ -29,6 +30,7 @@ import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchRestClientAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
@@ -47,6 +49,8 @@ import org.springframework.util.StringUtils;
@AutoConfiguration(after = ElasticsearchRestClientAutoConfiguration.class)
@ConditionalOnClass({ ElasticsearchVectorStore.class, EmbeddingModel.class, RestClient.class })
@EnableConfigurationProperties(ElasticsearchVectorStoreProperties.class)
@ConditionalOnProperty(name = SpringAIVectorStoreTypes.TYPE, havingValue = SpringAIVectorStoreTypes.ELASTICSEARCH,
matchIfMissing = true)
public class ElasticsearchVectorStoreAutoConfiguration {
@Bean

View File

@@ -34,6 +34,7 @@ import org.springframework.ai.retry.autoconfigure.SpringAiRetryAutoConfiguration
import org.springframework.ai.document.Document;
import org.springframework.ai.observation.conventions.VectorStoreProvider;
import org.springframework.ai.test.vectorstore.ObservationTestUtil;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.ai.vectorstore.elasticsearch.ElasticsearchVectorStore;
import org.springframework.ai.vectorstore.SearchRequest;
import org.springframework.ai.vectorstore.elasticsearch.SimilarityFunction;
@@ -149,6 +150,33 @@ class ElasticsearchVectorStoreAutoConfigurationIT {
});
}
@Test
public void autoConfigurationDisabledWhenTypeIsNone() {
this.contextRunner.withPropertyValues("spring.ai.vectorstore.type=none").run(context -> {
assertThat(context.getBeansOfType(ElasticsearchVectorStoreProperties.class)).isEmpty();
assertThat(context.getBeansOfType(ElasticsearchVectorStore.class)).isEmpty();
assertThat(context.getBeansOfType(VectorStore.class)).isEmpty();
});
}
@Test
public void autoConfigurationEnabledByDefault() {
this.contextRunner.run(context -> {
assertThat(context.getBeansOfType(ElasticsearchVectorStoreProperties.class)).isNotEmpty();
assertThat(context.getBeansOfType(VectorStore.class)).isNotEmpty();
assertThat(context.getBean(VectorStore.class)).isInstanceOf(ElasticsearchVectorStore.class);
});
}
@Test
public void autoConfigurationEnabledWhenTypeIsElasticsearch() {
this.contextRunner.withPropertyValues("spring.ai.vectorstore.type=elasticsearch").run(context -> {
assertThat(context.getBeansOfType(ElasticsearchVectorStoreProperties.class)).isNotEmpty();
assertThat(context.getBeansOfType(VectorStore.class)).isNotEmpty();
assertThat(context.getBean(VectorStore.class)).isInstanceOf(ElasticsearchVectorStore.class);
});
}
private String getText(String uri) {
var resource = new DefaultResourceLoader().getResource(uri);
try {

View File

@@ -21,6 +21,7 @@ import io.micrometer.observation.ObservationRegistry;
import org.springframework.ai.embedding.BatchingStrategy;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.embedding.TokenCountBatchingStrategy;
import org.springframework.ai.vectorstore.SpringAIVectorStoreTypes;
import org.springframework.ai.vectorstore.gemfire.GemFireVectorStore;
import org.springframework.ai.vectorstore.observation.VectorStoreObservationConvention;
import org.springframework.beans.factory.ObjectProvider;
@@ -41,7 +42,8 @@ import org.springframework.context.annotation.Bean;
@AutoConfiguration
@ConditionalOnClass({ GemFireVectorStore.class, EmbeddingModel.class })
@EnableConfigurationProperties(GemFireVectorStoreProperties.class)
@ConditionalOnProperty(prefix = "spring.ai.vectorstore.gemfire", value = { "index-name" })
@ConditionalOnProperty(name = SpringAIVectorStoreTypes.TYPE, havingValue = SpringAIVectorStoreTypes.GEMFIRE,
matchIfMissing = true)
public class GemFireVectorStoreAutoConfiguration {
@Bean

View File

@@ -185,6 +185,33 @@ class GemFireVectorStoreAutoConfigurationIT {
});
}
@Test
public void autoConfigurationDisabledWhenTypeIsNone() {
this.contextRunner.withPropertyValues("spring.ai.vectorstore.type=none").run(context -> {
assertThat(context.getBeansOfType(GemFireVectorStoreProperties.class)).isEmpty();
assertThat(context.getBeansOfType(GemFireVectorStore.class)).isEmpty();
assertThat(context.getBeansOfType(VectorStore.class)).isEmpty();
});
}
@Test
public void autoConfigurationEnabledByDefault() {
this.contextRunner.run(context -> {
assertThat(context.getBeansOfType(GemFireVectorStoreProperties.class)).isNotEmpty();
assertThat(context.getBeansOfType(VectorStore.class)).isNotEmpty();
assertThat(context.getBean(VectorStore.class)).isInstanceOf(GemFireVectorStore.class);
});
}
@Test
public void autoConfigurationEnabledWhenTypeIsGemfire() {
this.contextRunner.withPropertyValues("spring.ai.vectorstore.type=gemfire").run(context -> {
assertThat(context.getBeansOfType(GemFireVectorStoreProperties.class)).isNotEmpty();
assertThat(context.getBeansOfType(VectorStore.class)).isNotEmpty();
assertThat(context.getBean(VectorStore.class)).isInstanceOf(GemFireVectorStore.class);
});
}
private Map<String, Object> parseIndex(String json) {
try {
JsonNode rootNode = new ObjectMapper().readTree(json);

View File

@@ -21,15 +21,16 @@ import javax.sql.DataSource;
import io.micrometer.observation.ObservationRegistry;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.vectorstore.SpringAIVectorStoreTypes;
import org.springframework.ai.vectorstore.hanadb.HanaCloudVectorStore;
import org.springframework.ai.vectorstore.hanadb.HanaVectorEntity;
import org.springframework.ai.vectorstore.hanadb.HanaVectorRepository;
import org.springframework.ai.vectorstore.hanadb.autoconfigure.HanaCloudVectorStoreProperties;
import org.springframework.ai.vectorstore.observation.VectorStoreObservationConvention;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
@@ -45,6 +46,8 @@ import org.springframework.context.annotation.Bean;
@AutoConfiguration(after = { JpaRepositoriesAutoConfiguration.class })
@ConditionalOnClass({ HanaCloudVectorStore.class, DataSource.class, HanaVectorEntity.class })
@EnableConfigurationProperties(HanaCloudVectorStoreProperties.class)
@ConditionalOnProperty(name = SpringAIVectorStoreTypes.TYPE, havingValue = SpringAIVectorStoreTypes.HANADB,
matchIfMissing = true)
public class HanaCloudVectorStoreAutoConfiguration {
@Bean

View File

@@ -20,12 +20,14 @@ import io.micrometer.observation.ObservationRegistry;
import org.springframework.ai.embedding.BatchingStrategy;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.embedding.TokenCountBatchingStrategy;
import org.springframework.ai.vectorstore.SpringAIVectorStoreTypes;
import org.springframework.ai.vectorstore.mariadb.MariaDBVectorStore;
import org.springframework.ai.vectorstore.observation.VectorStoreObservationConvention;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
@@ -40,6 +42,8 @@ import javax.sql.DataSource;
@AutoConfiguration(after = JdbcTemplateAutoConfiguration.class)
@ConditionalOnClass({ MariaDBVectorStore.class, DataSource.class, JdbcTemplate.class })
@EnableConfigurationProperties(org.springframework.ai.vectorstore.mariadb.autoconfigure.MariaDbStoreProperties.class)
@ConditionalOnProperty(name = SpringAIVectorStoreTypes.TYPE, havingValue = SpringAIVectorStoreTypes.MARIADB,
matchIfMissing = true)
public class MariaDbStoreAutoConfiguration {
@Bean

View File

@@ -25,6 +25,7 @@ import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.observation.conventions.VectorStoreProvider;
import org.springframework.ai.transformers.TransformersEmbeddingModel;
import org.springframework.ai.vectorstore.SearchRequest;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.ai.vectorstore.mariadb.MariaDBVectorStore;
import org.springframework.ai.vectorstore.observation.VectorStoreObservationContext;
import org.springframework.boot.autoconfigure.AutoConfigurations;
@@ -179,6 +180,33 @@ public class MariaDbStoreAutoConfigurationIT {
});
}
@Test
public void autoConfigurationDisabledWhenTypeIsNone() {
this.contextRunner.withPropertyValues("spring.ai.vectorstore.type=none").run(context -> {
assertThat(context.getBeansOfType(MariaDbStoreProperties.class)).isEmpty();
assertThat(context.getBeansOfType(MariaDBVectorStore.class)).isEmpty();
assertThat(context.getBeansOfType(VectorStore.class)).isEmpty();
});
}
@Test
public void autoConfigurationEnabledByDefault() {
this.contextRunner.run(context -> {
assertThat(context.getBeansOfType(MariaDbStoreProperties.class)).isNotEmpty();
assertThat(context.getBeansOfType(VectorStore.class)).isNotEmpty();
assertThat(context.getBean(VectorStore.class)).isInstanceOf(MariaDBVectorStore.class);
});
}
@Test
public void autoConfigurationEnabledWhenTypeIsMariaDB() {
this.contextRunner.withPropertyValues("spring.ai.vectorstore.type=mariadb").run(context -> {
assertThat(context.getBeansOfType(MariaDbStoreProperties.class)).isNotEmpty();
assertThat(context.getBeansOfType(VectorStore.class)).isNotEmpty();
assertThat(context.getBean(VectorStore.class)).isInstanceOf(MariaDBVectorStore.class);
});
}
@Configuration(proxyBeanMethods = false)
static class Config {

View File

@@ -27,12 +27,14 @@ import io.milvus.param.MetricType;
import org.springframework.ai.embedding.BatchingStrategy;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.embedding.TokenCountBatchingStrategy;
import org.springframework.ai.vectorstore.SpringAIVectorStoreTypes;
import org.springframework.ai.vectorstore.milvus.MilvusVectorStore;
import org.springframework.ai.vectorstore.observation.VectorStoreObservationConvention;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.util.StringUtils;
@@ -48,6 +50,8 @@ import org.springframework.util.StringUtils;
@AutoConfiguration
@ConditionalOnClass({ MilvusVectorStore.class, EmbeddingModel.class })
@EnableConfigurationProperties({ MilvusServiceClientProperties.class, MilvusVectorStoreProperties.class })
@ConditionalOnProperty(name = SpringAIVectorStoreTypes.TYPE, havingValue = SpringAIVectorStoreTypes.MILVUS,
matchIfMissing = true)
public class MilvusVectorStoreAutoConfiguration {
@Bean

View File

@@ -33,6 +33,7 @@ import org.springframework.ai.test.vectorstore.ObservationTestUtil;
import org.springframework.ai.transformers.TransformersEmbeddingModel;
import org.springframework.ai.vectorstore.SearchRequest;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.ai.vectorstore.milvus.MilvusVectorStore;
import org.springframework.ai.vectorstore.observation.VectorStoreObservationContext;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
@@ -163,6 +164,40 @@ public class MilvusVectorStoreAutoConfigurationIT {
});
}
@Test
public void autoConfigurationDisabledWhenTypeIsNone() {
this.contextRunner.withPropertyValues("spring.ai.vectorstore.type=none").run(context -> {
assertThat(context.getBeansOfType(MilvusVectorStoreProperties.class)).isEmpty();
assertThat(context.getBeansOfType(MilvusVectorStore.class)).isEmpty();
assertThat(context.getBeansOfType(VectorStore.class)).isEmpty();
});
}
@Test
public void autoConfigurationEnabledByDefault() {
this.contextRunner
.withPropertyValues("spring.ai.vectorstore.milvus.client.host=" + milvus.getHost(),
"spring.ai.vectorstore.milvus.client.port=" + milvus.getMappedPort(19530))
.run(context -> {
assertThat(context.getBeansOfType(MilvusVectorStoreProperties.class)).isNotEmpty();
assertThat(context.getBeansOfType(VectorStore.class)).isNotEmpty();
assertThat(context.getBean(VectorStore.class)).isInstanceOf(MilvusVectorStore.class);
});
}
@Test
public void autoConfigurationEnabledWhenTypeIsMilvus() {
this.contextRunner
.withPropertyValues("spring.ai.vectorstore.milvus.client.host=" + milvus.getHost(),
"spring.ai.vectorstore.milvus.client.port=" + milvus.getMappedPort(19530))
.withPropertyValues("spring.ai.vectorstore.type=milvus")
.run(context -> {
assertThat(context.getBeansOfType(MilvusVectorStoreProperties.class)).isNotEmpty();
assertThat(context.getBeansOfType(VectorStore.class)).isNotEmpty();
assertThat(context.getBean(VectorStore.class)).isInstanceOf(MilvusVectorStore.class);
});
}
@Configuration(proxyBeanMethods = false)
static class Config {

View File

@@ -24,12 +24,14 @@ import io.micrometer.observation.ObservationRegistry;
import org.springframework.ai.embedding.BatchingStrategy;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.embedding.TokenCountBatchingStrategy;
import org.springframework.ai.vectorstore.SpringAIVectorStoreTypes;
import org.springframework.ai.vectorstore.mongodb.atlas.MongoDBAtlasVectorStore;
import org.springframework.ai.vectorstore.observation.VectorStoreObservationConvention;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.core.convert.converter.Converter;
@@ -51,6 +53,8 @@ import org.springframework.util.StringUtils;
@AutoConfiguration
@ConditionalOnClass({ MongoDBAtlasVectorStore.class, EmbeddingModel.class, MongoTemplate.class })
@EnableConfigurationProperties(MongoDBAtlasVectorStoreProperties.class)
@ConditionalOnProperty(name = SpringAIVectorStoreTypes.TYPE, havingValue = SpringAIVectorStoreTypes.MONGODB_ATLAS,
matchIfMissing = true)
public class MongoDBAtlasVectorStoreAutoConfiguration {
@Bean

View File

@@ -35,6 +35,7 @@ import org.springframework.ai.test.vectorstore.ObservationTestUtil;
import org.springframework.ai.vectorstore.SearchRequest;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.ai.vectorstore.filter.FilterExpressionBuilder;
import org.springframework.ai.vectorstore.mongodb.atlas.MongoDBAtlasVectorStore;
import org.springframework.ai.vectorstore.observation.VectorStoreObservationContext;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration;
@@ -162,6 +163,33 @@ class MongoDBAtlasVectorStoreAutoConfigurationIT {
});
}
@Test
public void autoConfigurationDisabledWhenTypeIsNone() {
this.contextRunner.withPropertyValues("spring.ai.vectorstore.type=none").run(context -> {
assertThat(context.getBeansOfType(MongoDBAtlasVectorStoreProperties.class)).isEmpty();
assertThat(context.getBeansOfType(MongoDBAtlasVectorStore.class)).isEmpty();
assertThat(context.getBeansOfType(VectorStore.class)).isEmpty();
});
}
@Test
public void autoConfigurationEnabledByDefault() {
this.contextRunner.run(context -> {
assertThat(context.getBeansOfType(MongoDBAtlasVectorStoreProperties.class)).isNotEmpty();
assertThat(context.getBeansOfType(VectorStore.class)).isNotEmpty();
assertThat(context.getBean(VectorStore.class)).isInstanceOf(MongoDBAtlasVectorStore.class);
});
}
@Test
public void autoConfigurationEnabledWhenTypeIsMongodbAtlas() {
this.contextRunner.withPropertyValues("spring.ai.vectorstore.type=mongodb-atlas").run(context -> {
assertThat(context.getBeansOfType(MongoDBAtlasVectorStoreProperties.class)).isNotEmpty();
assertThat(context.getBeansOfType(VectorStore.class)).isNotEmpty();
assertThat(context.getBean(VectorStore.class)).isInstanceOf(MongoDBAtlasVectorStore.class);
});
}
@Configuration(proxyBeanMethods = false)
static class Config {

View File

@@ -22,12 +22,14 @@ import org.neo4j.driver.Driver;
import org.springframework.ai.embedding.BatchingStrategy;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.embedding.TokenCountBatchingStrategy;
import org.springframework.ai.vectorstore.SpringAIVectorStoreTypes;
import org.springframework.ai.vectorstore.neo4j.Neo4jVectorStore;
import org.springframework.ai.vectorstore.observation.VectorStoreObservationConvention;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.neo4j.Neo4jAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
@@ -43,6 +45,8 @@ import org.springframework.context.annotation.Bean;
@AutoConfiguration(after = Neo4jAutoConfiguration.class)
@ConditionalOnClass({ Neo4jVectorStore.class, EmbeddingModel.class, Driver.class })
@EnableConfigurationProperties({ Neo4jVectorStoreProperties.class })
@ConditionalOnProperty(name = SpringAIVectorStoreTypes.TYPE, havingValue = SpringAIVectorStoreTypes.NEO4J,
matchIfMissing = true)
public class Neo4jVectorStoreAutoConfiguration {
@Bean

View File

@@ -34,6 +34,7 @@ import org.springframework.ai.test.vectorstore.ObservationTestUtil;
import org.springframework.ai.transformers.TransformersEmbeddingModel;
import org.springframework.ai.vectorstore.SearchRequest;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.ai.vectorstore.neo4j.Neo4jVectorStore;
import org.springframework.ai.vectorstore.observation.VectorStoreObservationContext;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.autoconfigure.neo4j.Neo4jAutoConfiguration;
@@ -114,6 +115,33 @@ public class Neo4jVectorStoreAutoConfigurationIT {
});
}
@Test
public void autoConfigurationDisabledWhenTypeIsNone() {
this.contextRunner.withPropertyValues("spring.ai.vectorstore.type=none").run(context -> {
assertThat(context.getBeansOfType(Neo4jVectorStoreProperties.class)).isEmpty();
assertThat(context.getBeansOfType(Neo4jVectorStore.class)).isEmpty();
assertThat(context.getBeansOfType(VectorStore.class)).isEmpty();
});
}
@Test
public void autoConfigurationEnabledByDefault() {
this.contextRunner.run(context -> {
assertThat(context.getBeansOfType(Neo4jVectorStoreProperties.class)).isNotEmpty();
assertThat(context.getBeansOfType(VectorStore.class)).isNotEmpty();
assertThat(context.getBean(VectorStore.class)).isInstanceOf(Neo4jVectorStore.class);
});
}
@Test
public void autoConfigurationEnabledWhenTypeIsNeo4j() {
this.contextRunner.withPropertyValues("spring.ai.vectorstore.type=neo4j").run(context -> {
assertThat(context.getBeansOfType(Neo4jVectorStoreProperties.class)).isNotEmpty();
assertThat(context.getBeansOfType(VectorStore.class)).isNotEmpty();
assertThat(context.getBean(VectorStore.class)).isInstanceOf(Neo4jVectorStore.class);
});
}
@Configuration(proxyBeanMethods = false)
static class Config {

View File

@@ -40,6 +40,7 @@ import software.amazon.awssdk.regions.Region;
import org.springframework.ai.embedding.BatchingStrategy;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.embedding.TokenCountBatchingStrategy;
import org.springframework.ai.vectorstore.SpringAIVectorStoreTypes;
import org.springframework.ai.vectorstore.opensearch.OpenSearchVectorStore;
import org.springframework.ai.vectorstore.observation.VectorStoreObservationConvention;
import org.springframework.beans.factory.ObjectProvider;
@@ -47,6 +48,7 @@ import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -55,6 +57,8 @@ import org.springframework.util.StringUtils;
@AutoConfiguration
@ConditionalOnClass({ OpenSearchVectorStore.class, EmbeddingModel.class, OpenSearchClient.class })
@EnableConfigurationProperties(OpenSearchVectorStoreProperties.class)
@ConditionalOnProperty(name = SpringAIVectorStoreTypes.TYPE, havingValue = SpringAIVectorStoreTypes.OPENSEARCH,
matchIfMissing = true)
public class OpenSearchVectorStoreAutoConfiguration {
@Bean

View File

@@ -37,6 +37,7 @@ import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.observation.conventions.VectorStoreProvider;
import org.springframework.ai.test.vectorstore.ObservationTestUtil;
import org.springframework.ai.transformers.TransformersEmbeddingModel;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.ai.vectorstore.opensearch.OpenSearchVectorStore;
import org.springframework.ai.vectorstore.SearchRequest;
import org.springframework.ai.vectorstore.observation.VectorStoreObservationContext;
@@ -142,6 +143,33 @@ class OpenSearchVectorStoreAutoConfigurationIT {
});
}
@Test
public void autoConfigurationDisabledWhenTypeIsNone() {
this.contextRunner.withPropertyValues("spring.ai.vectorstore.type=none").run(context -> {
assertThat(context.getBeansOfType(OpenSearchVectorStoreProperties.class)).isEmpty();
assertThat(context.getBeansOfType(OpenSearchVectorStore.class)).isEmpty();
assertThat(context.getBeansOfType(VectorStore.class)).isEmpty();
});
}
@Test
public void autoConfigurationEnabledByDefault() {
this.contextRunner.run(context -> {
assertThat(context.getBeansOfType(OpenSearchVectorStoreProperties.class)).isNotEmpty();
assertThat(context.getBeansOfType(VectorStore.class)).isNotEmpty();
assertThat(context.getBean(VectorStore.class)).isInstanceOf(OpenSearchVectorStore.class);
});
}
@Test
public void autoConfigurationEnabledWhenTypeIsOpensearch() {
this.contextRunner.withPropertyValues("spring.ai.vectorstore.type=opensearch").run(context -> {
assertThat(context.getBeansOfType(OpenSearchVectorStoreProperties.class)).isNotEmpty();
assertThat(context.getBeansOfType(VectorStore.class)).isNotEmpty();
assertThat(context.getBean(VectorStore.class)).isInstanceOf(OpenSearchVectorStore.class);
});
}
private String getText(String uri) {
var resource = new DefaultResourceLoader().getResource(uri);
try {

View File

@@ -23,12 +23,14 @@ import io.micrometer.observation.ObservationRegistry;
import org.springframework.ai.embedding.BatchingStrategy;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.embedding.TokenCountBatchingStrategy;
import org.springframework.ai.vectorstore.SpringAIVectorStoreTypes;
import org.springframework.ai.vectorstore.oracle.OracleVectorStore;
import org.springframework.ai.vectorstore.observation.VectorStoreObservationConvention;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
@@ -45,6 +47,8 @@ import org.springframework.jdbc.core.JdbcTemplate;
@AutoConfiguration(after = JdbcTemplateAutoConfiguration.class)
@ConditionalOnClass({ OracleVectorStore.class, DataSource.class, JdbcTemplate.class })
@EnableConfigurationProperties(OracleVectorStoreProperties.class)
@ConditionalOnProperty(name = SpringAIVectorStoreTypes.TYPE, havingValue = SpringAIVectorStoreTypes.ORACLE,
matchIfMissing = true)
public class OracleVectorStoreAutoConfiguration {
@Bean

View File

@@ -36,6 +36,7 @@ import org.springframework.ai.transformers.TransformersEmbeddingModel;
import org.springframework.ai.vectorstore.SearchRequest;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.ai.vectorstore.observation.VectorStoreObservationContext;
import org.springframework.ai.vectorstore.oracle.OracleVectorStore;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration;
@@ -124,6 +125,33 @@ public class OracleVectorStoreAutoConfigurationIT {
});
}
@Test
public void autoConfigurationDisabledWhenTypeIsNone() {
this.contextRunner.withPropertyValues("spring.ai.vectorstore.type=none").run(context -> {
assertThat(context.getBeansOfType(OracleVectorStoreProperties.class)).isEmpty();
assertThat(context.getBeansOfType(OracleVectorStore.class)).isEmpty();
assertThat(context.getBeansOfType(VectorStore.class)).isEmpty();
});
}
@Test
public void autoConfigurationEnabledByDefault() {
this.contextRunner.run(context -> {
assertThat(context.getBeansOfType(OracleVectorStoreProperties.class)).isNotEmpty();
assertThat(context.getBeansOfType(VectorStore.class)).isNotEmpty();
assertThat(context.getBean(VectorStore.class)).isInstanceOf(OracleVectorStore.class);
});
}
@Test
public void autoConfigurationEnabledWhenTypeIsOracle() {
this.contextRunner.withPropertyValues("spring.ai.vectorstore.type=oracle").run(context -> {
assertThat(context.getBeansOfType(OracleVectorStoreProperties.class)).isNotEmpty();
assertThat(context.getBeansOfType(VectorStore.class)).isNotEmpty();
assertThat(context.getBean(VectorStore.class)).isInstanceOf(OracleVectorStore.class);
});
}
@Configuration(proxyBeanMethods = false)
static class Config {

View File

@@ -23,12 +23,14 @@ import io.micrometer.observation.ObservationRegistry;
import org.springframework.ai.embedding.BatchingStrategy;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.embedding.TokenCountBatchingStrategy;
import org.springframework.ai.vectorstore.SpringAIVectorStoreTypes;
import org.springframework.ai.vectorstore.pgvector.PgVectorStore;
import org.springframework.ai.vectorstore.observation.VectorStoreObservationConvention;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
@@ -45,6 +47,8 @@ import org.springframework.jdbc.core.JdbcTemplate;
@AutoConfiguration(after = JdbcTemplateAutoConfiguration.class)
@ConditionalOnClass({ PgVectorStore.class, DataSource.class, JdbcTemplate.class })
@EnableConfigurationProperties(PgVectorStoreProperties.class)
@ConditionalOnProperty(name = SpringAIVectorStoreTypes.TYPE, havingValue = SpringAIVectorStoreTypes.PGVECTOR,
matchIfMissing = true)
public class PgVectorStoreAutoConfiguration {
@Bean

View File

@@ -34,6 +34,7 @@ import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.observation.conventions.VectorStoreProvider;
import org.springframework.ai.test.vectorstore.ObservationTestUtil;
import org.springframework.ai.transformers.TransformersEmbeddingModel;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.ai.vectorstore.pgvector.PgVectorStore;
import org.springframework.ai.vectorstore.SearchRequest;
import org.springframework.ai.vectorstore.observation.VectorStoreObservationContext;
@@ -163,6 +164,33 @@ public class PgVectorStoreAutoConfigurationIT {
.run(context -> assertThat(isFullyQualifiedTableExists(context, schemaName, tableName)).isFalse());
}
@Test
public void autoConfigurationDisabledWhenTypeIsNone() {
this.contextRunner.withPropertyValues("spring.ai.vectorstore.type=none").run(context -> {
assertThat(context.getBeansOfType(PgVectorStoreProperties.class)).isEmpty();
assertThat(context.getBeansOfType(PgVectorStore.class)).isEmpty();
assertThat(context.getBeansOfType(VectorStore.class)).isEmpty();
});
}
@Test
public void autoConfigurationEnabledByDefault() {
this.contextRunner.run(context -> {
assertThat(context.getBeansOfType(PgVectorStoreProperties.class)).isNotEmpty();
assertThat(context.getBeansOfType(VectorStore.class)).isNotEmpty();
assertThat(context.getBean(VectorStore.class)).isInstanceOf(PgVectorStore.class);
});
}
@Test
public void autoConfigurationEnabledWhenTypeIsPgvector() {
this.contextRunner.withPropertyValues("spring.ai.vectorstore.type=pgvector").run(context -> {
assertThat(context.getBeansOfType(PgVectorStoreProperties.class)).isNotEmpty();
assertThat(context.getBeansOfType(VectorStore.class)).isNotEmpty();
assertThat(context.getBean(VectorStore.class)).isInstanceOf(PgVectorStore.class);
});
}
@Configuration(proxyBeanMethods = false)
static class Config {

View File

@@ -21,12 +21,14 @@ import io.micrometer.observation.ObservationRegistry;
import org.springframework.ai.embedding.BatchingStrategy;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.embedding.TokenCountBatchingStrategy;
import org.springframework.ai.vectorstore.SpringAIVectorStoreTypes;
import org.springframework.ai.vectorstore.pinecone.PineconeVectorStore;
import org.springframework.ai.vectorstore.observation.VectorStoreObservationConvention;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
@@ -39,6 +41,8 @@ import org.springframework.context.annotation.Bean;
@AutoConfiguration
@ConditionalOnClass({ PineconeVectorStore.class, EmbeddingModel.class })
@EnableConfigurationProperties(PineconeVectorStoreProperties.class)
@ConditionalOnProperty(name = SpringAIVectorStoreTypes.TYPE, havingValue = SpringAIVectorStoreTypes.PINECONE,
matchIfMissing = true)
public class PineconeVectorStoreAutoConfiguration {
@Bean

View File

@@ -35,6 +35,7 @@ import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.observation.conventions.VectorStoreProvider;
import org.springframework.ai.test.vectorstore.ObservationTestUtil;
import org.springframework.ai.transformers.TransformersEmbeddingModel;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.ai.vectorstore.pinecone.PineconeVectorStore;
import org.springframework.ai.vectorstore.SearchRequest;
import org.springframework.ai.vectorstore.observation.VectorStoreObservationContext;
@@ -131,6 +132,33 @@ public class PineconeVectorStoreAutoConfigurationIT {
});
}
@Test
public void autoConfigurationDisabledWhenTypeIsNone() {
this.contextRunner.withPropertyValues("spring.ai.vectorstore.type=none").run(context -> {
assertThat(context.getBeansOfType(PineconeVectorStoreProperties.class)).isEmpty();
assertThat(context.getBeansOfType(PineconeVectorStore.class)).isEmpty();
assertThat(context.getBeansOfType(VectorStore.class)).isEmpty();
});
}
@Test
public void autoConfigurationEnabledByDefault() {
this.contextRunner.run(context -> {
assertThat(context.getBeansOfType(PineconeVectorStoreProperties.class)).isNotEmpty();
assertThat(context.getBeansOfType(VectorStore.class)).isNotEmpty();
assertThat(context.getBean(VectorStore.class)).isInstanceOf(PineconeVectorStore.class);
});
}
@Test
public void autoConfigurationEnabledWhenTypeIsPinecone() {
this.contextRunner.withPropertyValues("spring.ai.vectorstore.type=pinecone").run(context -> {
assertThat(context.getBeansOfType(PineconeVectorStoreProperties.class)).isNotEmpty();
assertThat(context.getBeansOfType(VectorStore.class)).isNotEmpty();
assertThat(context.getBean(VectorStore.class)).isInstanceOf(PineconeVectorStore.class);
});
}
@Configuration(proxyBeanMethods = false)
static class Config {

View File

@@ -23,12 +23,14 @@ import io.qdrant.client.QdrantGrpcClient;
import org.springframework.ai.embedding.BatchingStrategy;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.embedding.TokenCountBatchingStrategy;
import org.springframework.ai.vectorstore.SpringAIVectorStoreTypes;
import org.springframework.ai.vectorstore.observation.VectorStoreObservationConvention;
import org.springframework.ai.vectorstore.qdrant.QdrantVectorStore;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
@@ -44,6 +46,8 @@ import org.springframework.context.annotation.Bean;
@AutoConfiguration
@ConditionalOnClass({ QdrantVectorStore.class, EmbeddingModel.class })
@EnableConfigurationProperties(QdrantVectorStoreProperties.class)
@ConditionalOnProperty(name = SpringAIVectorStoreTypes.TYPE, havingValue = SpringAIVectorStoreTypes.QDRANT,
matchIfMissing = true)
public class QdrantVectorStoreAutoConfiguration {
@Bean

View File

@@ -35,6 +35,7 @@ import org.springframework.ai.transformers.TransformersEmbeddingModel;
import org.springframework.ai.vectorstore.SearchRequest;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.ai.vectorstore.observation.VectorStoreObservationContext;
import org.springframework.ai.vectorstore.qdrant.QdrantVectorStore;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.context.annotation.Bean;
@@ -114,6 +115,33 @@ public class QdrantVectorStoreAutoConfigurationIT {
});
}
@Test
public void autoConfigurationDisabledWhenTypeIsNone() {
this.contextRunner.withPropertyValues("spring.ai.vectorstore.type=none").run(context -> {
assertThat(context.getBeansOfType(QdrantVectorStoreProperties.class)).isEmpty();
assertThat(context.getBeansOfType(QdrantVectorStore.class)).isEmpty();
assertThat(context.getBeansOfType(VectorStore.class)).isEmpty();
});
}
@Test
public void autoConfigurationEnabledByDefault() {
this.contextRunner.run(context -> {
assertThat(context.getBeansOfType(QdrantVectorStoreProperties.class)).isNotEmpty();
assertThat(context.getBeansOfType(VectorStore.class)).isNotEmpty();
assertThat(context.getBean(VectorStore.class)).isInstanceOf(QdrantVectorStore.class);
});
}
@Test
public void autoConfigurationEnabledWhenTypeIsQdrant() {
this.contextRunner.withPropertyValues("spring.ai.vectorstore.type=qdrant").run(context -> {
assertThat(context.getBeansOfType(QdrantVectorStoreProperties.class)).isNotEmpty();
assertThat(context.getBeansOfType(VectorStore.class)).isNotEmpty();
assertThat(context.getBean(VectorStore.class)).isInstanceOf(QdrantVectorStore.class);
});
}
@Configuration(proxyBeanMethods = false)
static class Config {

View File

@@ -25,6 +25,7 @@ import redis.clients.jedis.JedisPooled;
import org.springframework.ai.embedding.BatchingStrategy;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.embedding.TokenCountBatchingStrategy;
import org.springframework.ai.vectorstore.SpringAIVectorStoreTypes;
import org.springframework.ai.vectorstore.redis.RedisVectorStore;
import org.springframework.ai.vectorstore.observation.VectorStoreObservationConvention;
import org.springframework.beans.factory.ObjectProvider;
@@ -32,6 +33,7 @@ import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
@@ -49,6 +51,8 @@ import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
@ConditionalOnClass({ JedisPooled.class, JedisConnectionFactory.class, RedisVectorStore.class, EmbeddingModel.class })
@ConditionalOnBean(JedisConnectionFactory.class)
@EnableConfigurationProperties(RedisVectorStoreProperties.class)
@ConditionalOnProperty(name = SpringAIVectorStoreTypes.TYPE, havingValue = SpringAIVectorStoreTypes.REDIS,
matchIfMissing = true)
public class RedisVectorStoreAutoConfiguration {
@Bean

View File

@@ -34,6 +34,7 @@ import org.springframework.ai.transformers.TransformersEmbeddingModel;
import org.springframework.ai.vectorstore.SearchRequest;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.ai.vectorstore.observation.VectorStoreObservationContext;
import org.springframework.ai.vectorstore.redis.RedisVectorStore;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
@@ -106,6 +107,33 @@ class RedisVectorStoreAutoConfigurationIT {
});
}
@Test
public void autoConfigurationDisabledWhenTypeIsNone() {
this.contextRunner.withPropertyValues("spring.ai.vectorstore.type=none").run(context -> {
assertThat(context.getBeansOfType(RedisVectorStoreProperties.class)).isEmpty();
assertThat(context.getBeansOfType(RedisVectorStore.class)).isEmpty();
assertThat(context.getBeansOfType(VectorStore.class)).isEmpty();
});
}
@Test
public void autoConfigurationEnabledByDefault() {
this.contextRunner.run(context -> {
assertThat(context.getBeansOfType(RedisVectorStoreProperties.class)).isNotEmpty();
assertThat(context.getBeansOfType(VectorStore.class)).isNotEmpty();
assertThat(context.getBean(VectorStore.class)).isInstanceOf(RedisVectorStore.class);
});
}
@Test
public void autoConfigurationEnabledWhenTypeIsRedis() {
this.contextRunner.withPropertyValues("spring.ai.vectorstore.type=redis").run(context -> {
assertThat(context.getBeansOfType(RedisVectorStoreProperties.class)).isNotEmpty();
assertThat(context.getBeansOfType(VectorStore.class)).isNotEmpty();
assertThat(context.getBean(VectorStore.class)).isInstanceOf(RedisVectorStore.class);
});
}
@Configuration(proxyBeanMethods = false)
static class Config {

View File

@@ -28,12 +28,14 @@ import org.typesense.resources.Node;
import org.springframework.ai.embedding.BatchingStrategy;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.embedding.TokenCountBatchingStrategy;
import org.springframework.ai.vectorstore.SpringAIVectorStoreTypes;
import org.springframework.ai.vectorstore.typesense.TypesenseVectorStore;
import org.springframework.ai.vectorstore.observation.VectorStoreObservationConvention;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
@@ -47,6 +49,8 @@ import org.springframework.context.annotation.Bean;
@AutoConfiguration
@ConditionalOnClass({ TypesenseVectorStore.class, EmbeddingModel.class })
@EnableConfigurationProperties({ TypesenseServiceClientProperties.class, TypesenseVectorStoreProperties.class })
@ConditionalOnProperty(name = SpringAIVectorStoreTypes.TYPE, havingValue = SpringAIVectorStoreTypes.TYPESENSE,
matchIfMissing = true)
public class TypesenseVectorStoreAutoConfiguration {
@Bean

View File

@@ -34,6 +34,7 @@ import org.springframework.ai.transformers.TransformersEmbeddingModel;
import org.springframework.ai.vectorstore.SearchRequest;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.ai.vectorstore.observation.VectorStoreObservationContext;
import org.springframework.ai.vectorstore.typesense.TypesenseVectorStore;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.context.annotation.Bean;
@@ -109,6 +110,33 @@ public class TypesenseVectorStoreAutoConfigurationIT {
});
}
@Test
public void autoConfigurationDisabledWhenTypeIsNone() {
this.contextRunner.withPropertyValues("spring.ai.vectorstore.type=none").run(context -> {
assertThat(context.getBeansOfType(TypesenseVectorStoreProperties.class)).isEmpty();
assertThat(context.getBeansOfType(TypesenseVectorStore.class)).isEmpty();
assertThat(context.getBeansOfType(VectorStore.class)).isEmpty();
});
}
@Test
public void autoConfigurationEnabledByDefault() {
this.contextRunner.run(context -> {
assertThat(context.getBeansOfType(TypesenseVectorStoreProperties.class)).isNotEmpty();
assertThat(context.getBeansOfType(VectorStore.class)).isNotEmpty();
assertThat(context.getBean(VectorStore.class)).isInstanceOf(TypesenseVectorStore.class);
});
}
@Test
public void autoConfigurationEnabledWhenTypeIsTypesense() {
this.contextRunner.withPropertyValues("spring.ai.vectorstore.type=typesense").run(context -> {
assertThat(context.getBeansOfType(TypesenseVectorStoreProperties.class)).isNotEmpty();
assertThat(context.getBeansOfType(VectorStore.class)).isNotEmpty();
assertThat(context.getBean(VectorStore.class)).isInstanceOf(TypesenseVectorStore.class);
});
}
@Configuration(proxyBeanMethods = false)
static class Config {

View File

@@ -25,12 +25,14 @@ import io.weaviate.client.v1.auth.exception.AuthException;
import org.springframework.ai.embedding.BatchingStrategy;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.embedding.TokenCountBatchingStrategy;
import org.springframework.ai.vectorstore.SpringAIVectorStoreTypes;
import org.springframework.ai.vectorstore.observation.VectorStoreObservationConvention;
import org.springframework.ai.vectorstore.weaviate.WeaviateVectorStore;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
@@ -44,6 +46,8 @@ import org.springframework.context.annotation.Bean;
@AutoConfiguration
@ConditionalOnClass({ EmbeddingModel.class, WeaviateVectorStore.class })
@EnableConfigurationProperties({ WeaviateVectorStoreProperties.class })
@ConditionalOnProperty(name = SpringAIVectorStoreTypes.TYPE, havingValue = SpringAIVectorStoreTypes.WEAVIATE,
matchIfMissing = true)
public class WeaviateVectorStoreAutoConfiguration {
@Bean

View File

@@ -33,6 +33,7 @@ import org.springframework.ai.transformers.TransformersEmbeddingModel;
import org.springframework.ai.vectorstore.SearchRequest;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.ai.vectorstore.observation.VectorStoreObservationContext;
import org.springframework.ai.vectorstore.weaviate.WeaviateVectorStore;
import org.springframework.ai.vectorstore.weaviate.WeaviateVectorStore.MetadataField;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
@@ -146,6 +147,33 @@ public class WeaviateVectorStoreAutoConfigurationIT {
});
}
@Test
public void autoConfigurationDisabledWhenTypeIsNone() {
this.contextRunner.withPropertyValues("spring.ai.vectorstore.type=none").run(context -> {
assertThat(context.getBeansOfType(WeaviateVectorStoreProperties.class)).isEmpty();
assertThat(context.getBeansOfType(WeaviateVectorStore.class)).isEmpty();
assertThat(context.getBeansOfType(VectorStore.class)).isEmpty();
});
}
@Test
public void autoConfigurationEnabledByDefault() {
this.contextRunner.run(context -> {
assertThat(context.getBeansOfType(WeaviateVectorStoreProperties.class)).isNotEmpty();
assertThat(context.getBeansOfType(VectorStore.class)).isNotEmpty();
assertThat(context.getBean(VectorStore.class)).isInstanceOf(WeaviateVectorStore.class);
});
}
@Test
public void autoConfigurationEnabledWhenTypeIsWeaviate() {
this.contextRunner.withPropertyValues("spring.ai.vectorstore.type=weaviate").run(context -> {
assertThat(context.getBeansOfType(WeaviateVectorStoreProperties.class)).isNotEmpty();
assertThat(context.getBeansOfType(VectorStore.class)).isNotEmpty();
assertThat(context.getBean(VectorStore.class)).isInstanceOf(WeaviateVectorStore.class);
});
}
@Configuration(proxyBeanMethods = false)
static class Config {

View File

@@ -0,0 +1,63 @@
/*
* Copyright 2023-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ai.vectorstore;
public class SpringAIVectorStoreTypes {
public static final String VECTOR_STORE_PREFIX = "spring.ai.vectorstore";
public static final String TYPE = VECTOR_STORE_PREFIX + ".type";
public static final String AZURE = "azure";
public static final String AZURE_COSMOS_DB = "azure-cosmos-db";
public static final String CASSANDRA = "cassandra";
public static final String CHROMA = "chroma";
public static final String ELASTICSEARCH = "elasticsearch";
public static final String GEMFIRE = "gemfire";
public static final String HANADB = "hanadb";
public static final String MARIADB = "mariadb";
public static final String MILVUS = "milvus";
public static final String MONGODB_ATLAS = "mongodb-atlas";
public static final String NEO4J = "neo4j";
public static final String OPENSEARCH = "opensearch";
public static final String ORACLE = "oracle";
public static final String PGVECTOR = "pgvector";
public static final String PINECONE = "pinecone";
public static final String QDRANT = "qdrant";
public static final String REDIS = "redis";
public static final String TYPESENSE = "typesense";
public static final String WEAVIATE = "weaviate";
}