diff --git a/spring-ai-core/src/main/java/org/springframework/ai/embedding/package-info.java b/spring-ai-core/src/main/java/org/springframework/ai/embedding/package-info.java new file mode 100644 index 000000000..e28a215d4 --- /dev/null +++ b/spring-ai-core/src/main/java/org/springframework/ai/embedding/package-info.java @@ -0,0 +1,25 @@ +/* + * Copyright 2023-2024 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. + */ + +/** + * Provides the API for embedding observations. + */ +@NonNullApi +@NonNullFields +package org.springframework.ai.embedding; + +import org.springframework.lang.NonNullApi; +import org.springframework.lang.NonNullFields; diff --git a/spring-ai-core/src/main/java/org/springframework/ai/vectorstore/AbstractVectorStoreBuilder.java b/spring-ai-core/src/main/java/org/springframework/ai/vectorstore/AbstractVectorStoreBuilder.java index 0affbdcc8..8ee7f88b5 100644 --- a/spring-ai-core/src/main/java/org/springframework/ai/vectorstore/AbstractVectorStoreBuilder.java +++ b/spring-ai-core/src/main/java/org/springframework/ai/vectorstore/AbstractVectorStoreBuilder.java @@ -33,13 +33,18 @@ import org.springframework.util.Assert; public abstract class AbstractVectorStoreBuilder> implements VectorStore.Builder { - protected EmbeddingModel embeddingModel; + protected final EmbeddingModel embeddingModel; protected ObservationRegistry observationRegistry = ObservationRegistry.NOOP; @Nullable protected VectorStoreObservationConvention customObservationConvention; + public AbstractVectorStoreBuilder(EmbeddingModel embeddingModel) { + Assert.notNull(embeddingModel, "EmbeddingModel must be configured"); + this.embeddingModel = embeddingModel; + } + public EmbeddingModel getEmbeddingModel() { return this.embeddingModel; } @@ -71,20 +76,9 @@ public abstract class AbstractVectorStoreBuilder { + private SimpleVectorStoreBuilder(EmbeddingModel embeddingModel) { + super(embeddingModel); + } + @Override public SimpleVectorStore build() { - validate(); return new SimpleVectorStore(this); } diff --git a/spring-ai-core/src/main/java/org/springframework/ai/vectorstore/VectorStore.java b/spring-ai-core/src/main/java/org/springframework/ai/vectorstore/VectorStore.java index faea243a7..5c2dd00da 100644 --- a/spring-ai-core/src/main/java/org/springframework/ai/vectorstore/VectorStore.java +++ b/spring-ai-core/src/main/java/org/springframework/ai/vectorstore/VectorStore.java @@ -23,7 +23,6 @@ import io.micrometer.observation.ObservationRegistry; import org.springframework.ai.document.Document; import org.springframework.ai.document.DocumentWriter; -import org.springframework.ai.embedding.EmbeddingModel; import org.springframework.ai.vectorstore.observation.DefaultVectorStoreObservationConvention; import org.springframework.ai.vectorstore.observation.VectorStoreObservationConvention; import org.springframework.lang.Nullable; @@ -59,6 +58,7 @@ public interface VectorStore extends DocumentWriter { * @param idList list of document ids for which documents will be removed. * @return Returns true if the documents were successfully deleted. */ + @Nullable Optional delete(List idList); /** @@ -68,6 +68,7 @@ public interface VectorStore extends DocumentWriter { * topK, similarity threshold and metadata filter expressions. * @return Returns documents th match the query request conditions. */ + @Nullable List similaritySearch(SearchRequest request); /** @@ -77,6 +78,7 @@ public interface VectorStore extends DocumentWriter { * @return Returns a list of documents that have embeddings similar to the query text * embedding. */ + @Nullable default List similaritySearch(String query) { return this.similaritySearch(SearchRequest.query(query)); } @@ -90,8 +92,6 @@ public interface VectorStore extends DocumentWriter { */ interface Builder> { - T embeddingModel(EmbeddingModel embeddingModel); - /** * Sets the registry for collecting observations and metrics. Defaults to * {@link ObservationRegistry#NOOP} if not specified. diff --git a/spring-ai-core/src/main/java/org/springframework/ai/vectorstore/observation/AbstractObservationVectorStore.java b/spring-ai-core/src/main/java/org/springframework/ai/vectorstore/observation/AbstractObservationVectorStore.java index 81e704d99..ec6c641be 100644 --- a/spring-ai-core/src/main/java/org/springframework/ai/vectorstore/observation/AbstractObservationVectorStore.java +++ b/spring-ai-core/src/main/java/org/springframework/ai/vectorstore/observation/AbstractObservationVectorStore.java @@ -45,7 +45,6 @@ public abstract class AbstractObservationVectorStore implements VectorStore { @Nullable private final VectorStoreObservationConvention customObservationConvention; - @Nullable protected final EmbeddingModel embeddingModel; /** @@ -59,8 +58,7 @@ public abstract class AbstractObservationVectorStore implements VectorStore { this(null, observationRegistry, customObservationConvention); } - private AbstractObservationVectorStore(@Nullable EmbeddingModel embeddingModel, - ObservationRegistry observationRegistry, + private AbstractObservationVectorStore(EmbeddingModel embeddingModel, ObservationRegistry observationRegistry, @Nullable VectorStoreObservationConvention customObservationConvention) { this.embeddingModel = embeddingModel; this.observationRegistry = observationRegistry; @@ -94,6 +92,7 @@ public abstract class AbstractObservationVectorStore implements VectorStore { } @Override + @Nullable public Optional delete(List deleteDocIds) { VectorStoreObservationContext observationContext = this @@ -107,6 +106,7 @@ public abstract class AbstractObservationVectorStore implements VectorStore { } @Override + @Nullable public List similaritySearch(SearchRequest request) { VectorStoreObservationContext searchObservationContext = this diff --git a/spring-ai-core/src/test/java/org/springframework/ai/vectorstore/SimpleVectorStoreTests.java b/spring-ai-core/src/test/java/org/springframework/ai/vectorstore/SimpleVectorStoreTests.java index 41bdbb457..6e05264a6 100644 --- a/spring-ai-core/src/test/java/org/springframework/ai/vectorstore/SimpleVectorStoreTests.java +++ b/spring-ai-core/src/test/java/org/springframework/ai/vectorstore/SimpleVectorStoreTests.java @@ -57,7 +57,7 @@ class SimpleVectorStoreTests { when(this.mockEmbeddingModel.dimensions()).thenReturn(3); when(this.mockEmbeddingModel.embed(any(String.class))).thenReturn(new float[] { 0.1f, 0.2f, 0.3f }); when(this.mockEmbeddingModel.embed(any(Document.class))).thenReturn(new float[] { 0.1f, 0.2f, 0.3f }); - this.vectorStore = new SimpleVectorStore(SimpleVectorStore.builder().embeddingModel(this.mockEmbeddingModel)); + this.vectorStore = new SimpleVectorStore(SimpleVectorStore.builder(this.mockEmbeddingModel)); } @Test diff --git a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/vectorstore/azure/AzureVectorStoreAutoConfiguration.java b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/vectorstore/azure/AzureVectorStoreAutoConfiguration.java index 7db2a7936..d3f702a2a 100644 --- a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/vectorstore/azure/AzureVectorStoreAutoConfiguration.java +++ b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/vectorstore/azure/AzureVectorStoreAutoConfiguration.java @@ -84,9 +84,7 @@ public class AzureVectorStoreAutoConfiguration { ObjectProvider customObservationConvention, BatchingStrategy batchingStrategy) { - var builder = AzureVectorStore.builder() - .searchIndexClient(searchIndexClient) - .embeddingModel(embeddingModel) + var builder = AzureVectorStore.builder(searchIndexClient, embeddingModel) .initializeSchema(properties.isInitializeSchema()) .filterMetadataFields(List.of()) .observationRegistry(observationRegistry.getIfUnique(() -> ObservationRegistry.NOOP)) diff --git a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/vectorstore/cassandra/CassandraVectorStoreAutoConfiguration.java b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/vectorstore/cassandra/CassandraVectorStoreAutoConfiguration.java index 64890673b..2e63baf7a 100644 --- a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/vectorstore/cassandra/CassandraVectorStoreAutoConfiguration.java +++ b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/vectorstore/cassandra/CassandraVectorStoreAutoConfiguration.java @@ -62,7 +62,7 @@ public class CassandraVectorStoreAutoConfiguration { ObjectProvider customObservationConvention, BatchingStrategy batchingStrategy) { - return CassandraVectorStore.builder() + return CassandraVectorStore.builder(embeddingModel) .session(cqlSession) .keyspace(properties.getKeyspace()) .table(properties.getTable()) @@ -72,7 +72,6 @@ public class CassandraVectorStoreAutoConfiguration { .fixedThreadPoolExecutorSize(properties.getFixedThreadPoolExecutorSize()) .disallowSchemaChanges(!properties.isInitializeSchema()) .returnEmbeddings(properties.getReturnEmbeddings()) - .embeddingModel(embeddingModel) .observationRegistry(observationRegistry.getIfUnique(() -> ObservationRegistry.NOOP)) .customObservationConvention(customObservationConvention.getIfAvailable(() -> null)) .batchingStrategy(batchingStrategy) diff --git a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/vectorstore/chroma/ChromaVectorStoreAutoConfiguration.java b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/vectorstore/chroma/ChromaVectorStoreAutoConfiguration.java index 50f758918..898a04444 100644 --- a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/vectorstore/chroma/ChromaVectorStoreAutoConfiguration.java +++ b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/vectorstore/chroma/ChromaVectorStoreAutoConfiguration.java @@ -86,9 +86,7 @@ public class ChromaVectorStoreAutoConfiguration { ChromaVectorStoreProperties storeProperties, ObjectProvider observationRegistry, ObjectProvider customObservationConvention, BatchingStrategy chromaBatchingStrategy) { - return ChromaVectorStore.builder() - .chromaApi(chromaApi) - .embeddingModel(embeddingModel) + return ChromaVectorStore.builder(chromaApi, embeddingModel) .collectionName(storeProperties.getCollectionName()) .initializeSchema(storeProperties.isInitializeSchema()) .observationRegistry(observationRegistry.getIfUnique(() -> ObservationRegistry.NOOP)) diff --git a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/vectorstore/elasticsearch/ElasticsearchVectorStoreAutoConfiguration.java b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/vectorstore/elasticsearch/ElasticsearchVectorStoreAutoConfiguration.java index 33d0c2810..8541e8e83 100644 --- a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/vectorstore/elasticsearch/ElasticsearchVectorStoreAutoConfiguration.java +++ b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/vectorstore/elasticsearch/ElasticsearchVectorStoreAutoConfiguration.java @@ -73,10 +73,8 @@ public class ElasticsearchVectorStoreAutoConfiguration { elasticsearchVectorStoreOptions.setSimilarity(properties.getSimilarity()); } - return ElasticsearchVectorStore.builder() - .restClient(restClient) + return ElasticsearchVectorStore.builder(restClient, embeddingModel) .options(elasticsearchVectorStoreOptions) - .embeddingModel(embeddingModel) .initializeSchema(properties.isInitializeSchema()) .observationRegistry(observationRegistry.getIfUnique(() -> ObservationRegistry.NOOP)) .customObservationConvention(customObservationConvention.getIfAvailable(() -> null)) diff --git a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/vectorstore/gemfire/GemFireVectorStoreAutoConfiguration.java b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/vectorstore/gemfire/GemFireVectorStoreAutoConfiguration.java index 5b2ae6d1c..26eb432cd 100644 --- a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/vectorstore/gemfire/GemFireVectorStoreAutoConfiguration.java +++ b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/vectorstore/gemfire/GemFireVectorStoreAutoConfiguration.java @@ -64,7 +64,7 @@ public class GemFireVectorStoreAutoConfiguration { ObjectProvider customObservationConvention, BatchingStrategy batchingStrategy) { - return GemFireVectorStore.builder() + return GemFireVectorStore.builder(embeddingModel) .host(gemFireConnectionDetails.getHost()) .port(gemFireConnectionDetails.getPort()) .indexName(properties.getIndexName()) @@ -74,7 +74,6 @@ public class GemFireVectorStoreAutoConfiguration { .vectorSimilarityFunction(properties.getVectorSimilarityFunction()) .fields(properties.getFields()) .sslEnabled(properties.isSslEnabled()) - .embeddingModel(embeddingModel) .initializeSchema(properties.isInitializeSchema()) .observationRegistry(observationRegistry.getIfUnique(() -> ObservationRegistry.NOOP)) .customObservationConvention(customObservationConvention.getIfAvailable(() -> null)) diff --git a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/vectorstore/hanadb/HanaCloudVectorStoreAutoConfiguration.java b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/vectorstore/hanadb/HanaCloudVectorStoreAutoConfiguration.java index 8c0c85628..3870f8d60 100644 --- a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/vectorstore/hanadb/HanaCloudVectorStoreAutoConfiguration.java +++ b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/vectorstore/hanadb/HanaCloudVectorStoreAutoConfiguration.java @@ -53,9 +53,7 @@ public class HanaCloudVectorStoreAutoConfiguration { ObjectProvider observationRegistry, ObjectProvider customObservationConvention) { - return HanaCloudVectorStore.builder() - .repository(repository) - .embeddingModel(embeddingModel) + return HanaCloudVectorStore.builder(repository, embeddingModel) .tableName(properties.getTableName()) .topK(properties.getTopK()) .observationRegistry(observationRegistry.getIfUnique(() -> ObservationRegistry.NOOP)) diff --git a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/vectorstore/mariadb/MariaDbStoreAutoConfiguration.java b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/vectorstore/mariadb/MariaDbStoreAutoConfiguration.java index b5b69e53e..e3c72674e 100644 --- a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/vectorstore/mariadb/MariaDbStoreAutoConfiguration.java +++ b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/vectorstore/mariadb/MariaDbStoreAutoConfiguration.java @@ -57,8 +57,7 @@ public class MariaDbStoreAutoConfiguration { var initializeSchema = properties.isInitializeSchema(); - return MariaDBVectorStore.builder(jdbcTemplate) - .embeddingModel(embeddingModel) + return MariaDBVectorStore.builder(jdbcTemplate, embeddingModel) .schemaName(properties.getSchemaName()) .vectorTableName(properties.getTableName()) .schemaValidation(properties.isSchemaValidation()) diff --git a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/vectorstore/milvus/MilvusVectorStoreAutoConfiguration.java b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/vectorstore/milvus/MilvusVectorStoreAutoConfiguration.java index 1dc3eb5df..029a1be61 100644 --- a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/vectorstore/milvus/MilvusVectorStoreAutoConfiguration.java +++ b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/vectorstore/milvus/MilvusVectorStoreAutoConfiguration.java @@ -71,9 +71,7 @@ public class MilvusVectorStoreAutoConfiguration { ObjectProvider observationRegistry, ObjectProvider customObservationConvention) { - return MilvusVectorStore.builder() - .milvusClient(milvusClient) - .embeddingModel(embeddingModel) + return MilvusVectorStore.builder(milvusClient, embeddingModel) .initializeSchema(properties.isInitializeSchema()) .batchingStrategy(batchingStrategy) .observationRegistry(observationRegistry.getIfUnique(() -> ObservationRegistry.NOOP)) diff --git a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/vectorstore/mongo/MongoDBAtlasVectorStoreAutoConfiguration.java b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/vectorstore/mongo/MongoDBAtlasVectorStoreAutoConfiguration.java index ec3a9eb98..8bb976346 100644 --- a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/vectorstore/mongo/MongoDBAtlasVectorStoreAutoConfiguration.java +++ b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/vectorstore/mongo/MongoDBAtlasVectorStoreAutoConfiguration.java @@ -66,9 +66,7 @@ public class MongoDBAtlasVectorStoreAutoConfiguration { ObjectProvider customObservationConvention, BatchingStrategy batchingStrategy) { - MongoDBAtlasVectorStore.MongoDBBuilder builder = MongoDBAtlasVectorStore.builder() - .mongoTemplate(mongoTemplate) - .embeddingModel(embeddingModel) + MongoDBAtlasVectorStore.MongoDBBuilder builder = MongoDBAtlasVectorStore.builder(mongoTemplate, embeddingModel) .initializeSchema(properties.isInitializeSchema()) .observationRegistry(observationRegistry.getIfUnique(() -> ObservationRegistry.NOOP)) .customObservationConvention(customObservationConvention.getIfAvailable(() -> null)) diff --git a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/vectorstore/neo4j/Neo4jVectorStoreAutoConfiguration.java b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/vectorstore/neo4j/Neo4jVectorStoreAutoConfiguration.java index aac5576d1..5d3d114c1 100644 --- a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/vectorstore/neo4j/Neo4jVectorStoreAutoConfiguration.java +++ b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/vectorstore/neo4j/Neo4jVectorStoreAutoConfiguration.java @@ -58,9 +58,7 @@ public class Neo4jVectorStoreAutoConfiguration { ObjectProvider customObservationConvention, BatchingStrategy batchingStrategy) { - return Neo4jVectorStore.builder() - .driver(driver) - .embeddingModel(embeddingModel) + return Neo4jVectorStore.builder(driver, embeddingModel) .initializeSchema(properties.isInitializeSchema()) .observationRegistry(observationRegistry.getIfUnique(() -> ObservationRegistry.NOOP)) .customObservationConvention(customObservationConvention.getIfAvailable(() -> null)) diff --git a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/vectorstore/opensearch/OpenSearchVectorStoreAutoConfiguration.java b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/vectorstore/opensearch/OpenSearchVectorStoreAutoConfiguration.java index 28a4e4529..b844e9bbf 100644 --- a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/vectorstore/opensearch/OpenSearchVectorStoreAutoConfiguration.java +++ b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/vectorstore/opensearch/OpenSearchVectorStoreAutoConfiguration.java @@ -79,10 +79,8 @@ public class OpenSearchVectorStoreAutoConfiguration { var mappingJson = Optional.ofNullable(properties.getMappingJson()) .orElse(OpenSearchVectorStore.DEFAULT_MAPPING_EMBEDDING_TYPE_KNN_VECTOR_DIMENSION); - return OpenSearchVectorStore.builder() + return OpenSearchVectorStore.builder(openSearchClient, embeddingModel) .index(indexName) - .openSearchClient(openSearchClient) - .embeddingModel(embeddingModel) .mappingJson(mappingJson) .initializeSchema(properties.isInitializeSchema()) .observationRegistry(observationRegistry.getIfUnique(() -> ObservationRegistry.NOOP)) diff --git a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/vectorstore/oracle/OracleVectorStoreAutoConfiguration.java b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/vectorstore/oracle/OracleVectorStoreAutoConfiguration.java index f8fcff20d..5e2d22b69 100644 --- a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/vectorstore/oracle/OracleVectorStoreAutoConfiguration.java +++ b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/vectorstore/oracle/OracleVectorStoreAutoConfiguration.java @@ -60,9 +60,7 @@ public class OracleVectorStoreAutoConfiguration { ObjectProvider customObservationConvention, BatchingStrategy batchingStrategy) { - return OracleVectorStore.builder() - .jdbcTemplate(jdbcTemplate) - .embeddingModel(embeddingModel) + return OracleVectorStore.builder(jdbcTemplate, embeddingModel) .tableName(properties.getTableName()) .indexType(properties.getIndexType()) .distanceType(properties.getDistanceType()) diff --git a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/vectorstore/pgvector/PgVectorStoreAutoConfiguration.java b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/vectorstore/pgvector/PgVectorStoreAutoConfiguration.java index 441aca334..95075ed20 100644 --- a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/vectorstore/pgvector/PgVectorStoreAutoConfiguration.java +++ b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/vectorstore/pgvector/PgVectorStoreAutoConfiguration.java @@ -62,9 +62,7 @@ public class PgVectorStoreAutoConfiguration { var initializeSchema = properties.isInitializeSchema(); - return PgVectorStore.builder() - .jdbcTemplate(jdbcTemplate) - .embeddingModel(embeddingModel) + return PgVectorStore.builder(jdbcTemplate, embeddingModel) .schemaName(properties.getSchemaName()) .vectorTableName(properties.getTableName()) .vectorTableValidationsEnabled(properties.isSchemaValidation()) diff --git a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/vectorstore/pinecone/PineconeVectorStoreAutoConfiguration.java b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/vectorstore/pinecone/PineconeVectorStoreAutoConfiguration.java index ba39ecec7..f56d596c1 100644 --- a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/vectorstore/pinecone/PineconeVectorStoreAutoConfiguration.java +++ b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/vectorstore/pinecone/PineconeVectorStoreAutoConfiguration.java @@ -55,8 +55,7 @@ public class PineconeVectorStoreAutoConfiguration { ObjectProvider customObservationConvention, BatchingStrategy batchingStrategy) { - return PineconeVectorStore.builder() - .embeddingModel(embeddingModel) + return PineconeVectorStore.builder(embeddingModel) .apiKey(properties.getApiKey()) .environment(properties.getEnvironment()) .projectId(properties.getProjectId()) diff --git a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/vectorstore/qdrant/QdrantVectorStoreAutoConfiguration.java b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/vectorstore/qdrant/QdrantVectorStoreAutoConfiguration.java index 790b53c3a..0521484be 100644 --- a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/vectorstore/qdrant/QdrantVectorStoreAutoConfiguration.java +++ b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/vectorstore/qdrant/QdrantVectorStoreAutoConfiguration.java @@ -77,9 +77,8 @@ public class QdrantVectorStoreAutoConfiguration { QdrantClient qdrantClient, ObjectProvider observationRegistry, ObjectProvider customObservationConvention, BatchingStrategy batchingStrategy) { - return QdrantVectorStore.builder(qdrantClient) + return QdrantVectorStore.builder(qdrantClient, embeddingModel) .collectionName(properties.getCollectionName()) - .embeddingModel(embeddingModel) .initializeSchema(properties.isInitializeSchema()) .observationRegistry(observationRegistry.getIfUnique(() -> ObservationRegistry.NOOP)) .customObservationConvention(customObservationConvention.getIfAvailable(() -> null)) diff --git a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/vectorstore/redis/RedisVectorStoreAutoConfiguration.java b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/vectorstore/redis/RedisVectorStoreAutoConfiguration.java index 42516395c..9b3187671 100644 --- a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/vectorstore/redis/RedisVectorStoreAutoConfiguration.java +++ b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/vectorstore/redis/RedisVectorStoreAutoConfiguration.java @@ -60,9 +60,9 @@ public class RedisVectorStoreAutoConfiguration { ObjectProvider customObservationConvention, BatchingStrategy batchingStrategy) { - return RedisVectorStore.builder() - .jedis(new JedisPooled(jedisConnectionFactory.getHostName(), jedisConnectionFactory.getPort())) - .embeddingModel(embeddingModel) + JedisPooled jedisPooled = new JedisPooled(jedisConnectionFactory.getHostName(), + jedisConnectionFactory.getPort()); + return RedisVectorStore.builder(jedisPooled, embeddingModel) .initializeSchema(properties.isInitializeSchema()) .observationRegistry(observationRegistry.getIfUnique(() -> ObservationRegistry.NOOP)) .customObservationConvention(customObservationConvention.getIfAvailable(() -> null)) diff --git a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/vectorstore/typesense/TypesenseVectorStoreAutoConfiguration.java b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/vectorstore/typesense/TypesenseVectorStoreAutoConfiguration.java index 9d259a274..823c32566 100644 --- a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/vectorstore/typesense/TypesenseVectorStoreAutoConfiguration.java +++ b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/vectorstore/typesense/TypesenseVectorStoreAutoConfiguration.java @@ -70,9 +70,7 @@ public class TypesenseVectorStoreAutoConfiguration { ObjectProvider customObservationConvention, BatchingStrategy batchingStrategy) { - return TypesenseVectorStore.builder() - .client(typesenseClient) - .embeddingModel(embeddingModel) + return TypesenseVectorStore.builder(typesenseClient, embeddingModel) .collectionName(properties.getCollectionName()) .embeddingDimension(properties.getEmbeddingDimension()) .initializeSchema(properties.isInitializeSchema()) diff --git a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/vectorstore/weaviate/WeaviateVectorStoreAutoConfiguration.java b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/vectorstore/weaviate/WeaviateVectorStoreAutoConfiguration.java index 1e7101700..3fd8d7c51 100644 --- a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/vectorstore/weaviate/WeaviateVectorStoreAutoConfiguration.java +++ b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/vectorstore/weaviate/WeaviateVectorStoreAutoConfiguration.java @@ -81,9 +81,7 @@ public class WeaviateVectorStoreAutoConfiguration { ObjectProvider customObservationConvention, BatchingStrategy batchingStrategy) { - return WeaviateVectorStore.builder() - .weaviateClient(weaviateClient) - .embeddingModel(embeddingModel) + return WeaviateVectorStore.builder(weaviateClient, embeddingModel) .objectClass(properties.getObjectClass()) .filterMetadataFields(properties.getFilterField() .entrySet() diff --git a/vector-stores/spring-ai-azure-cosmos-db-store/src/main/java/org/springframework/ai/vectorstore/cosmosdb/CosmosDBVectorStore.java b/vector-stores/spring-ai-azure-cosmos-db-store/src/main/java/org/springframework/ai/vectorstore/cosmosdb/CosmosDBVectorStore.java index 8de1f30d3..34a2d89fd 100644 --- a/vector-stores/spring-ai-azure-cosmos-db-store/src/main/java/org/springframework/ai/vectorstore/cosmosdb/CosmosDBVectorStore.java +++ b/vector-stores/spring-ai-azure-cosmos-db-store/src/main/java/org/springframework/ai/vectorstore/cosmosdb/CosmosDBVectorStore.java @@ -132,9 +132,7 @@ public class CosmosDBVectorStore extends AbstractObservationVectorStore implemen public CosmosDBVectorStore(ObservationRegistry observationRegistry, VectorStoreObservationConvention customObservationConvention, CosmosAsyncClient cosmosClient, CosmosDBVectorStoreConfig properties, EmbeddingModel embeddingModel, BatchingStrategy batchingStrategy) { - this(builder().cosmosClient(cosmosClient) - .embeddingModel(embeddingModel) - .containerName(properties.getContainerName()) + this(builder(cosmosClient, embeddingModel).containerName(properties.getContainerName()) .databaseName(properties.getDatabaseName()) .partitionKeyPath(properties.getPartitionKeyPath()) .vectorStoreThroughput(properties.getVectorStoreThroughput()) @@ -171,8 +169,8 @@ public class CosmosDBVectorStore extends AbstractObservationVectorStore implemen initializeContainer(containerName, databaseName, vectorStoreThroughput, vectorDimensions, partitionKeyPath); } - public static CosmosDBBuilder builder() { - return new CosmosDBBuilder(); + public static CosmosDBBuilder builder(CosmosAsyncClient cosmosClient, EmbeddingModel embeddingModel) { + return new CosmosDBBuilder(cosmosClient, embeddingModel); } private void initializeContainer(String containerName, String databaseName, int vectorStoreThroughput, @@ -430,7 +428,7 @@ public class CosmosDBVectorStore extends AbstractObservationVectorStore implemen */ public static class CosmosDBBuilder extends AbstractVectorStoreBuilder { - private CosmosAsyncClient cosmosClient; + private final CosmosAsyncClient cosmosClient; private String containerName; @@ -452,10 +450,10 @@ public class CosmosDBVectorStore extends AbstractObservationVectorStore implemen * @return the builder instance * @throws IllegalArgumentException if cosmosClient is null */ - public CosmosDBBuilder cosmosClient(CosmosAsyncClient cosmosClient) { + public CosmosDBBuilder(CosmosAsyncClient cosmosClient, EmbeddingModel embeddingModel) { + super(embeddingModel); Assert.notNull(cosmosClient, "CosmosClient must not be null"); this.cosmosClient = cosmosClient; - return this; } /** @@ -543,7 +541,6 @@ public class CosmosDBVectorStore extends AbstractObservationVectorStore implemen @Override public CosmosDBVectorStore build() { - validate(); return new CosmosDBVectorStore(this); } diff --git a/vector-stores/spring-ai-azure-cosmos-db-store/src/test/java/org/springframework/ai/vectorstore/cosmosdb/CosmosDBVectorStoreIT.java b/vector-stores/spring-ai-azure-cosmos-db-store/src/test/java/org/springframework/ai/vectorstore/cosmosdb/CosmosDBVectorStoreIT.java index 10acb4c69..1b07505d9 100644 --- a/vector-stores/spring-ai-azure-cosmos-db-store/src/test/java/org/springframework/ai/vectorstore/cosmosdb/CosmosDBVectorStoreIT.java +++ b/vector-stores/spring-ai-azure-cosmos-db-store/src/test/java/org/springframework/ai/vectorstore/cosmosdb/CosmosDBVectorStoreIT.java @@ -167,13 +167,11 @@ public class CosmosDBVectorStoreIT { @Bean public VectorStore vectorStore(CosmosAsyncClient cosmosClient, EmbeddingModel embeddingModel, VectorStoreObservationConvention convention) { - return CosmosDBVectorStore.builder() + return CosmosDBVectorStore.builder(cosmosClient, embeddingModel) .databaseName("test-database") .containerName("test-container") .metadataFields(List.of("country", "year", "city")) .vectorStoreThroughput(1000) - .cosmosClient(cosmosClient) - .embeddingModel(embeddingModel) .customObservationConvention(convention) .build(); } diff --git a/vector-stores/spring-ai-azure-store/src/main/java/org/springframework/ai/vectorstore/azure/AzureVectorStore.java b/vector-stores/spring-ai-azure-store/src/main/java/org/springframework/ai/vectorstore/azure/AzureVectorStore.java index 0151927e0..1e0364e59 100644 --- a/vector-stores/spring-ai-azure-store/src/main/java/org/springframework/ai/vectorstore/azure/AzureVectorStore.java +++ b/vector-stores/spring-ai-azure-store/src/main/java/org/springframework/ai/vectorstore/azure/AzureVectorStore.java @@ -173,9 +173,7 @@ public class AzureVectorStore extends AbstractObservationVectorStore implements boolean initializeSchema, List filterMetadataFields, ObservationRegistry observationRegistry, VectorStoreObservationConvention customObservationConvention, BatchingStrategy batchingStrategy) { - this(builder().searchIndexClient(searchIndexClient) - .embeddingModel(embeddingModel) - .initializeSchema(initializeSchema) + this(builder(searchIndexClient, embeddingModel).initializeSchema(initializeSchema) .filterMetadataFields(filterMetadataFields) .observationRegistry(observationRegistry) .customObservationConvention(customObservationConvention) @@ -203,8 +201,8 @@ public class AzureVectorStore extends AbstractObservationVectorStore implements this.filterExpressionConverter = new AzureAiSearchFilterExpressionConverter(filterMetadataFields); } - public static AzureBuilder builder() { - return new AzureBuilder(); + public static AzureBuilder builder(SearchIndexClient searchIndexClient, EmbeddingModel embeddingModel) { + return new AzureBuilder(searchIndexClient, embeddingModel); } /** @@ -469,7 +467,7 @@ public class AzureVectorStore extends AbstractObservationVectorStore implements */ public static class AzureBuilder extends AbstractVectorStoreBuilder { - private SearchIndexClient searchIndexClient; + private final SearchIndexClient searchIndexClient; private boolean initializeSchema = false; @@ -489,10 +487,10 @@ public class AzureVectorStore extends AbstractObservationVectorStore implements * @return the builder instance * @throws IllegalArgumentException if searchIndexClient is null */ - public AzureBuilder searchIndexClient(SearchIndexClient searchIndexClient) { + public AzureBuilder(SearchIndexClient searchIndexClient, EmbeddingModel embeddingModel) { + super(embeddingModel); Assert.notNull(searchIndexClient, "SearchIndexClient must not be null"); this.searchIndexClient = searchIndexClient; - return this; } /** @@ -567,7 +565,6 @@ public class AzureVectorStore extends AbstractObservationVectorStore implements @Override public AzureVectorStore build() { - validate(); return new AzureVectorStore(this); } diff --git a/vector-stores/spring-ai-azure-store/src/test/java/org/springframework/ai/vectorstore/azure/AzureVectorStoreIT.java b/vector-stores/spring-ai-azure-store/src/test/java/org/springframework/ai/vectorstore/azure/AzureVectorStoreIT.java index abf622a30..380cfff2b 100644 --- a/vector-stores/spring-ai-azure-store/src/test/java/org/springframework/ai/vectorstore/azure/AzureVectorStoreIT.java +++ b/vector-stores/spring-ai-azure-store/src/test/java/org/springframework/ai/vectorstore/azure/AzureVectorStoreIT.java @@ -310,9 +310,7 @@ public class AzureVectorStoreIT { @Bean public VectorStore vectorStore(SearchIndexClient searchIndexClient, EmbeddingModel embeddingModel) { - return AzureVectorStore.builder() - .searchIndexClient(searchIndexClient) - .embeddingModel(embeddingModel) + return AzureVectorStore.builder(searchIndexClient, embeddingModel) .initializeSchema(true) .filterMetadataFields(List.of(MetadataField.text("country"), MetadataField.int64("year"), MetadataField.date("activationDate"))) diff --git a/vector-stores/spring-ai-azure-store/src/test/java/org/springframework/ai/vectorstore/azure/AzureVectorStoreObservationIT.java b/vector-stores/spring-ai-azure-store/src/test/java/org/springframework/ai/vectorstore/azure/AzureVectorStoreObservationIT.java index 59f905c19..0c4da707f 100644 --- a/vector-stores/spring-ai-azure-store/src/test/java/org/springframework/ai/vectorstore/azure/AzureVectorStoreObservationIT.java +++ b/vector-stores/spring-ai-azure-store/src/test/java/org/springframework/ai/vectorstore/azure/AzureVectorStoreObservationIT.java @@ -183,9 +183,7 @@ public class AzureVectorStoreObservationIT { @Bean public VectorStore vectorStore(SearchIndexClient searchIndexClient, EmbeddingModel embeddingModel, ObservationRegistry observationRegistry) { - return AzureVectorStore.builder() - .searchIndexClient(searchIndexClient) - .embeddingModel(embeddingModel) + return AzureVectorStore.builder(searchIndexClient, embeddingModel) .initializeSchema(true) .filterMetadataFields(List.of(MetadataField.text("country"), MetadataField.int64("year"), MetadataField.date("activationDate"))) diff --git a/vector-stores/spring-ai-cassandra-store/src/main/java/org/springframework/ai/vectorstore/cassandra/CassandraVectorStore.java b/vector-stores/spring-ai-cassandra-store/src/main/java/org/springframework/ai/vectorstore/cassandra/CassandraVectorStore.java index b6790a367..bb7ad63fb 100644 --- a/vector-stores/spring-ai-cassandra-store/src/main/java/org/springframework/ai/vectorstore/cassandra/CassandraVectorStore.java +++ b/vector-stores/spring-ai-cassandra-store/src/main/java/org/springframework/ai/vectorstore/cassandra/CassandraVectorStore.java @@ -249,8 +249,7 @@ public class CassandraVectorStore extends AbstractObservationVectorStore impleme public CassandraVectorStore(CassandraVectorStoreConfig conf, EmbeddingModel embeddingModel, ObservationRegistry observationRegistry, VectorStoreObservationConvention customObservationConvention, BatchingStrategy batchingStrategy) { - this(builder().session(conf.session) - .embeddingModel(embeddingModel) + this(builder(embeddingModel).session(conf.session) .observationRegistry(observationRegistry) .customObservationConvention(customObservationConvention) .batchingStrategy(batchingStrategy)); @@ -289,8 +288,8 @@ public class CassandraVectorStore extends AbstractObservationVectorStore impleme this.returnEmbeddings = builder.returnEmbeddings; } - public static CassandraBuilder builder() { - return new CassandraBuilder(); + public static CassandraBuilder builder(EmbeddingModel embeddingModel) { + return new CassandraBuilder(embeddingModel); } private static Float[] toFloatArray(float[] embedding) { @@ -827,16 +826,9 @@ public class CassandraVectorStore extends AbstractObservationVectorStore impleme private boolean returnEmbeddings = false; - /** - * Executor to use when adding documents. The hotspot is the call to the - * embeddingModel. For remote transformers you probably want a higher value to - * utilize network. For local transformers you probably want a lower value to - * avoid saturation. - **/ - public CassandraBuilder fixedThreadPoolExecutorSize(int threads) { - Preconditions.checkArgument(0 < threads); - this.fixedThreadPoolExecutorSize = threads; - return this; + private CassandraBuilder(EmbeddingModel embeddingModel) { + super(embeddingModel); + Assert.notNull(session, "Session must not be null"); } /** @@ -851,6 +843,18 @@ public class CassandraVectorStore extends AbstractObservationVectorStore impleme return this; } + /** + * Executor to use when adding documents. The hotspot is the call to the + * embeddingModel. For remote transformers you probably want a higher value to + * utilize network. For local transformers you probably want a lower value to + * avoid saturation. + **/ + public CassandraBuilder fixedThreadPoolExecutorSize(int threads) { + Preconditions.checkArgument(0 < threads); + this.fixedThreadPoolExecutorSize = threads; + return this; + } + /** * Sets the keyspace name. * @param keyspace the keyspace name @@ -1073,7 +1077,6 @@ public class CassandraVectorStore extends AbstractObservationVectorStore impleme @Override public CassandraVectorStore build() { - validate(); if (session == null && sessionBuilder != null) { session = sessionBuilder.build(); closeSessionOnClose = true; diff --git a/vector-stores/spring-ai-cassandra-store/src/test/java/org/springframework/ai/vectorstore/cassandra/CassandraRichSchemaVectorStoreIT.java b/vector-stores/spring-ai-cassandra-store/src/test/java/org/springframework/ai/vectorstore/cassandra/CassandraRichSchemaVectorStoreIT.java index a48cb29e9..98820eb1a 100644 --- a/vector-stores/spring-ai-cassandra-store/src/test/java/org/springframework/ai/vectorstore/cassandra/CassandraRichSchemaVectorStoreIT.java +++ b/vector-stores/spring-ai-cassandra-store/src/test/java/org/springframework/ai/vectorstore/cassandra/CassandraRichSchemaVectorStoreIT.java @@ -120,7 +120,7 @@ class CassandraRichSchemaVectorStoreIT { List partitionKeys = List.of(wikiSC, langSC, titleSC); List clusteringKeys = List.of(chunkNoSC); - return CassandraVectorStore.builder() + return CassandraVectorStore.builder(context.getBean(EmbeddingModel.class)) .session(context.getBean(CqlSession.class)) .keyspace("test_wikidata") .table("articles") @@ -253,7 +253,6 @@ class CassandraRichSchemaVectorStoreIT { this.contextRunner.run(context -> { try (CassandraVectorStore store = storeBuilder(context, List.of()).fixedThreadPoolExecutorSize(nThreads) - .embeddingModel(context.getBean(EmbeddingModel.class)) .build()) { var executor = Executors.newFixedThreadPool((int) (nThreads * 1.2)); @@ -552,7 +551,6 @@ class CassandraRichSchemaVectorStoreIT { CassandraVectorStore.dropKeyspace(builder); } - builder.embeddingModel(context.getBean(EmbeddingModel.class)); return new CassandraVectorStore(builder); } @@ -569,7 +567,6 @@ class CassandraRichSchemaVectorStoreIT { CassandraVectorStore.dropKeyspace(builder); } - builder.embeddingModel(context.getBean(EmbeddingModel.class)); return builder; } diff --git a/vector-stores/spring-ai-cassandra-store/src/test/java/org/springframework/ai/vectorstore/cassandra/CassandraVectorStoreIT.java b/vector-stores/spring-ai-cassandra-store/src/test/java/org/springframework/ai/vectorstore/cassandra/CassandraVectorStoreIT.java index b86a95086..f25b4aab5 100644 --- a/vector-stores/spring-ai-cassandra-store/src/test/java/org/springframework/ai/vectorstore/cassandra/CassandraVectorStoreIT.java +++ b/vector-stores/spring-ai-cassandra-store/src/test/java/org/springframework/ai/vectorstore/cassandra/CassandraVectorStoreIT.java @@ -85,14 +85,16 @@ class CassandraVectorStoreIT { } } - private static CassandraVectorStore.CassandraBuilder storeBuilder(CqlSession cqlSession) { - return CassandraVectorStore.builder() + private static CassandraVectorStore.CassandraBuilder storeBuilder(CqlSession cqlSession, + EmbeddingModel embeddingModel) { + return CassandraVectorStore.builder(embeddingModel) .session(cqlSession) .keyspace("test_" + CassandraVectorStore.DEFAULT_KEYSPACE_NAME); } private static CassandraVectorStore createTestStore(ApplicationContext context, SchemaColumn... metadataFields) { - CassandraVectorStore.CassandraBuilder builder = storeBuilder(context.getBean(CqlSession.class)) + CassandraVectorStore.CassandraBuilder builder = storeBuilder(context.getBean(CqlSession.class), + context.getBean(EmbeddingModel.class)) .addMetadataColumns(metadataFields); return createTestStore(context, builder); @@ -101,7 +103,6 @@ class CassandraVectorStoreIT { private static CassandraVectorStore createTestStore(ApplicationContext context, CassandraVectorStore.CassandraBuilder builder) { CassandraVectorStore.dropKeyspace(builder); - builder.embeddingModel(context.getBean(EmbeddingModel.class)); CassandraVectorStore store = builder.build(); return store; } @@ -149,7 +150,8 @@ class CassandraVectorStoreIT { @Test void addAndSearchReturnEmbeddings() { this.contextRunner.run(context -> { - CassandraVectorStore.CassandraBuilder builder = storeBuilder(context.getBean(CqlSession.class)) + CassandraVectorStore.CassandraBuilder builder = storeBuilder(context.getBean(CqlSession.class), + context.getBean(EmbeddingModel.class)) .returnEmbeddings(true); try (CassandraVectorStore store = createTestStore(context, builder)) { @@ -395,12 +397,11 @@ class CassandraVectorStoreIT { @Bean public CassandraVectorStore store(CqlSession cqlSession, EmbeddingModel embeddingModel) { - CassandraVectorStore.CassandraBuilder builder = storeBuilder(cqlSession) - .addMetadataColumns(new CassandraVectorStore.SchemaColumn("meta1", DataTypes.TEXT), - new CassandraVectorStore.SchemaColumn("meta2", DataTypes.TEXT), - new CassandraVectorStore.SchemaColumn("country", DataTypes.TEXT), - new CassandraVectorStore.SchemaColumn("year", DataTypes.SMALLINT)) - .embeddingModel(embeddingModel); + CassandraVectorStore.CassandraBuilder builder = storeBuilder(cqlSession, embeddingModel).addMetadataColumns( + new CassandraVectorStore.SchemaColumn("meta1", DataTypes.TEXT), + new CassandraVectorStore.SchemaColumn("meta2", DataTypes.TEXT), + new CassandraVectorStore.SchemaColumn("country", DataTypes.TEXT), + new CassandraVectorStore.SchemaColumn("year", DataTypes.SMALLINT)); CassandraVectorStore.dropKeyspace(builder); return builder.build(); diff --git a/vector-stores/spring-ai-cassandra-store/src/test/java/org/springframework/ai/vectorstore/cassandra/CassandraVectorStoreObservationIT.java b/vector-stores/spring-ai-cassandra-store/src/test/java/org/springframework/ai/vectorstore/cassandra/CassandraVectorStoreObservationIT.java index 6aba243e6..f65e7508f 100644 --- a/vector-stores/spring-ai-cassandra-store/src/test/java/org/springframework/ai/vectorstore/cassandra/CassandraVectorStoreObservationIT.java +++ b/vector-stores/spring-ai-cassandra-store/src/test/java/org/springframework/ai/vectorstore/cassandra/CassandraVectorStoreObservationIT.java @@ -172,7 +172,7 @@ public class CassandraVectorStoreObservationIT { public CassandraVectorStore store(CqlSession cqlSession, EmbeddingModel embeddingModel, ObservationRegistry observationRegistry) { - CassandraVectorStore.CassandraBuilder builder = CassandraVectorStore.builder() + CassandraVectorStore.CassandraBuilder builder = CassandraVectorStore.builder(embeddingModel) .session(cqlSession) .session(cqlSession) .keyspace("test_" + CassandraVectorStore.DEFAULT_KEYSPACE_NAME) @@ -180,7 +180,6 @@ public class CassandraVectorStoreObservationIT { new CassandraVectorStore.SchemaColumn("meta2", DataTypes.TEXT), new CassandraVectorStore.SchemaColumn("country", DataTypes.TEXT), new CassandraVectorStore.SchemaColumn("year", DataTypes.SMALLINT)) - .embeddingModel(embeddingModel) .observationRegistry(observationRegistry) .batchingStrategy(new TokenCountBatchingStrategy()); diff --git a/vector-stores/spring-ai-cassandra-store/src/test/java/org/springframework/ai/vectorstore/cassandra/WikiVectorStoreExample.java b/vector-stores/spring-ai-cassandra-store/src/test/java/org/springframework/ai/vectorstore/cassandra/WikiVectorStoreExample.java index 82846a2d6..66a4261b3 100644 --- a/vector-stores/spring-ai-cassandra-store/src/test/java/org/springframework/ai/vectorstore/cassandra/WikiVectorStoreExample.java +++ b/vector-stores/spring-ai-cassandra-store/src/test/java/org/springframework/ai/vectorstore/cassandra/WikiVectorStoreExample.java @@ -93,7 +93,7 @@ class WikiVectorStoreExample { List extraColumns = List.of(new SchemaColumn("revision", DataTypes.INT), new SchemaColumn("id", DataTypes.INT)); - return CassandraVectorStore.builder() + return CassandraVectorStore.builder(embeddingModel) .session(cqlSession) .keyspace("wikidata") .table("articles") @@ -118,7 +118,6 @@ class WikiVectorStoreExample { int chunk_no = 0 < parts.length ? Integer.parseInt(parts[1]) : 0; return List.of("simplewiki", "en", title, chunk_no, 0); }) - .embeddingModel(embeddingModel()) .build(); } diff --git a/vector-stores/spring-ai-chroma-store/src/main/java/org/springframework/ai/chroma/vectorstore/ChromaApi.java b/vector-stores/spring-ai-chroma-store/src/main/java/org/springframework/ai/chroma/vectorstore/ChromaApi.java index c67a969c8..04c12129d 100644 --- a/vector-stores/spring-ai-chroma-store/src/main/java/org/springframework/ai/chroma/vectorstore/ChromaApi.java +++ b/vector-stores/spring-ai-chroma-store/src/main/java/org/springframework/ai/chroma/vectorstore/ChromaApi.java @@ -33,6 +33,7 @@ import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; import org.springframework.http.client.SimpleClientHttpRequestFactory; import org.springframework.http.client.support.BasicAuthenticationInterceptor; +import org.springframework.lang.Nullable; import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; import org.springframework.web.client.HttpClientErrorException; @@ -58,6 +59,7 @@ public class ChromaApi { private RestClient restClient; + @Nullable private String keyToken; public ChromaApi(String baseUrl) { @@ -99,7 +101,7 @@ public class ChromaApi { return this; } - public List toEmbeddingResponseList(QueryResponse queryResponse) { + public List toEmbeddingResponseList(@Nullable QueryResponse queryResponse) { List result = new ArrayList<>(); if (queryResponse != null && !CollectionUtils.isEmpty(queryResponse.ids())) { @@ -113,6 +115,7 @@ public class ChromaApi { return result; } + @Nullable public Collection createCollection(CreateCollectionRequest createCollectionRequest) { return this.restClient.post() @@ -138,6 +141,7 @@ public class ChromaApi { .toBodilessEntity(); } + @Nullable public Collection getCollection(String collectionName) { try { @@ -157,6 +161,7 @@ public class ChromaApi { } } + @Nullable public List listCollections() { return this.restClient.get() @@ -167,7 +172,7 @@ public class ChromaApi { .getBody(); } - public void upsertEmbeddings(String collectionId, AddEmbeddingsRequest embedding) { + public void upsertEmbeddings(@Nullable String collectionId, AddEmbeddingsRequest embedding) { this.restClient.post() .uri("/api/v1/collections/{collection_id}/upsert", collectionId) @@ -177,7 +182,7 @@ public class ChromaApi { .toBodilessEntity(); } - public int deleteEmbeddings(String collectionId, DeleteEmbeddingsRequest deleteRequest) { + public int deleteEmbeddings(@Nullable String collectionId, DeleteEmbeddingsRequest deleteRequest) { return this.restClient.post() .uri("/api/v1/collections/{collection_id}/delete", collectionId) .headers(this::httpHeaders) @@ -188,6 +193,7 @@ public class ChromaApi { .value(); } + @Nullable public Long countEmbeddings(String collectionId) { return this.restClient.get() @@ -198,7 +204,8 @@ public class ChromaApi { .getBody(); } - public QueryResponse queryCollection(String collectionId, QueryRequest queryRequest) { + @Nullable + public QueryResponse queryCollection(@Nullable String collectionId, QueryRequest queryRequest) { return this.restClient.post() .uri("/api/v1/collections/{collection_id}/query", collectionId) @@ -212,7 +219,7 @@ public class ChromaApi { // // Chroma Client API (https://docs.trychroma.com/js_reference/Client) // - + @Nullable public GetEmbeddingResponse getEmbeddings(String collectionId, GetEmbeddingsRequest getEmbeddingsRequest) { return this.restClient.post() @@ -332,7 +339,7 @@ public class ChromaApi { @JsonInclude(JsonInclude.Include.NON_NULL) public record DeleteEmbeddingsRequest(// @formatter:off @JsonProperty("ids") List ids, - @JsonProperty("where") Map where) { // @formatter:on + @Nullable @JsonProperty("where") Map where) { // @formatter:on public DeleteEmbeddingsRequest(List ids) { this(ids, null); @@ -353,7 +360,7 @@ public class ChromaApi { @JsonInclude(JsonInclude.Include.NON_NULL) public record GetEmbeddingsRequest(// @formatter:off @JsonProperty("ids") List ids, - @JsonProperty("where") Map where, + @Nullable @JsonProperty("where") Map where, @JsonProperty("limit") Integer limit, @JsonProperty("offset") Integer offset, @JsonProperty("include") List include) { // @formatter:on @@ -404,7 +411,7 @@ public class ChromaApi { public record QueryRequest(// @formatter:off @JsonProperty("query_embeddings") List queryEmbeddings, @JsonProperty("n_results") Integer nResults, - @JsonProperty("where") Map where, + @Nullable @JsonProperty("where") Map where, @JsonProperty("include") List include) { // @formatter:on /** @@ -414,7 +421,7 @@ public class ChromaApi { this(List.of(queryEmbedding), nResults, null, Include.all); } - public QueryRequest(float[] queryEmbedding, Integer nResults, Map where) { + public QueryRequest(float[] queryEmbedding, Integer nResults, @Nullable Map where) { this(List.of(queryEmbedding), nResults, CollectionUtils.isEmpty(where) ? null : where, Include.all); } @@ -471,7 +478,7 @@ public class ChromaApi { @JsonProperty("id") String id, @JsonProperty("embedding") float[] embedding, @JsonProperty("document") String document, - @JsonProperty("metadata") Map metadata, + @Nullable @JsonProperty("metadata") Map metadata, @JsonProperty("distances") Double distances) { // @formatter:on } diff --git a/vector-stores/spring-ai-chroma-store/src/main/java/org/springframework/ai/chroma/vectorstore/ChromaVectorStore.java b/vector-stores/spring-ai-chroma-store/src/main/java/org/springframework/ai/chroma/vectorstore/ChromaVectorStore.java index 1773804d1..bed32ec93 100644 --- a/vector-stores/spring-ai-chroma-store/src/main/java/org/springframework/ai/chroma/vectorstore/ChromaVectorStore.java +++ b/vector-stores/spring-ai-chroma-store/src/main/java/org/springframework/ai/chroma/vectorstore/ChromaVectorStore.java @@ -100,11 +100,9 @@ public class ChromaVectorStore extends AbstractObservationVectorStore implements @Deprecated(since = "1.0.0-M5", forRemoval = true) public ChromaVectorStore(EmbeddingModel embeddingModel, ChromaApi chromaApi, String collectionName, boolean initializeSchema, ObservationRegistry observationRegistry, - VectorStoreObservationConvention customObservationConvention, BatchingStrategy batchingStrategy) { + @Nullable VectorStoreObservationConvention customObservationConvention, BatchingStrategy batchingStrategy) { - this(builder().chromaApi(chromaApi) - .embeddingModel(embeddingModel) - .collectionName(collectionName) + this(builder(chromaApi, embeddingModel).collectionName(collectionName) .initializeSchema(initializeSchema) .observationRegistry(observationRegistry) .customObservationConvention(customObservationConvention) @@ -117,8 +115,6 @@ public class ChromaVectorStore extends AbstractObservationVectorStore implements protected ChromaVectorStore(ChromaBuilder builder) { super(builder); - Assert.notNull(builder.chromaApi, "ChromaApi must not be null"); - this.chromaApi = builder.chromaApi; this.collectionName = builder.collectionName; this.initializeSchema = builder.initializeSchema; @@ -136,6 +132,10 @@ public class ChromaVectorStore extends AbstractObservationVectorStore implements } } + public static ChromaBuilder builder(ChromaApi chromaApi, EmbeddingModel embeddingModel) { + return new ChromaBuilder(chromaApi, embeddingModel); + } + @Override public void afterPropertiesSet() throws Exception { if (!this.initialized) { @@ -150,15 +150,13 @@ public class ChromaVectorStore extends AbstractObservationVectorStore implements + " doesn't exist and won't be created as the initializeSchema is set to false."); } } - this.collectionId = collection.id(); + if (collection != null) { + this.collectionId = collection.id(); + } this.initialized = true; } } - public static ChromaBuilder builder() { - return new ChromaBuilder(); - } - @Override public void doAdd(@NonNull List documents) { Assert.notNull(documents, "Documents must not be null"); @@ -177,7 +175,7 @@ public class ChromaVectorStore extends AbstractObservationVectorStore implements for (Document document : documents) { ids.add(document.getId()); metadatas.add(document.getMetadata()); - contents.add(document.getContent()); + contents.add(document.getText()); embeddings.add(documentEmbeddings.get(documents.indexOf(document))); } @@ -278,7 +276,7 @@ public class ChromaVectorStore extends AbstractObservationVectorStore implements public static class ChromaBuilder extends AbstractVectorStoreBuilder { - private ChromaApi chromaApi; + private final ChromaApi chromaApi; private String collectionName = DEFAULT_COLLECTION_NAME; @@ -290,10 +288,10 @@ public class ChromaVectorStore extends AbstractObservationVectorStore implements private boolean initializeImmediately = false; - public ChromaBuilder chromaApi(ChromaApi chromaApi) { + private ChromaBuilder(ChromaApi chromaApi, EmbeddingModel embeddingModel) { + super(embeddingModel); Assert.notNull(chromaApi, "ChromaApi must not be null"); this.chromaApi = chromaApi; - return this; } /** @@ -358,7 +356,6 @@ public class ChromaVectorStore extends AbstractObservationVectorStore implements * @throws IllegalStateException if the builder is in an invalid state */ public ChromaVectorStore build() { - validate(); return new ChromaVectorStore(this); } diff --git a/vector-stores/spring-ai-chroma-store/src/test/java/org/springframework/ai/chroma/vectorstore/BasicAuthChromaWhereIT.java b/vector-stores/spring-ai-chroma-store/src/test/java/org/springframework/ai/chroma/vectorstore/BasicAuthChromaWhereIT.java index 8654f7d5b..7b966a1c9 100644 --- a/vector-stores/spring-ai-chroma-store/src/test/java/org/springframework/ai/chroma/vectorstore/BasicAuthChromaWhereIT.java +++ b/vector-stores/spring-ai-chroma-store/src/test/java/org/springframework/ai/chroma/vectorstore/BasicAuthChromaWhereIT.java @@ -111,9 +111,7 @@ public class BasicAuthChromaWhereIT { @Bean public VectorStore chromaVectorStore(EmbeddingModel embeddingModel, ChromaApi chromaApi) { - return ChromaVectorStore.builder() - .chromaApi(chromaApi) - .embeddingModel(embeddingModel) + return ChromaVectorStore.builder(chromaApi, embeddingModel) .collectionName("TestCollection") .initializeSchema(true) .build(); diff --git a/vector-stores/spring-ai-chroma-store/src/test/java/org/springframework/ai/chroma/vectorstore/ChromaApiIT.java b/vector-stores/spring-ai-chroma-store/src/test/java/org/springframework/ai/chroma/vectorstore/ChromaApiIT.java index f0c5b1511..270dcd306 100644 --- a/vector-stores/spring-ai-chroma-store/src/test/java/org/springframework/ai/chroma/vectorstore/ChromaApiIT.java +++ b/vector-stores/spring-ai-chroma-store/src/test/java/org/springframework/ai/chroma/vectorstore/ChromaApiIT.java @@ -207,9 +207,7 @@ public class ChromaApiIT { assertThat(collection).isNotNull(); assertThat(collection.name()).isEqualTo("test-collection"); - ChromaVectorStore store = ChromaVectorStore.builder() - .chromaApi(this.chromaApi) - .embeddingModel(this.embeddingModel) + ChromaVectorStore store = ChromaVectorStore.builder(this.chromaApi, this.embeddingModel) .collectionName("test-collection") .initializeImmediately(true) .build(); @@ -220,8 +218,7 @@ public class ChromaApiIT { @Test void shouldCreateNewCollectionWhenSchemaInitializationEnabled() { - ChromaVectorStore store = new ChromaVectorStore.ChromaBuilder().chromaApi(this.chromaApi) - .embeddingModel(this.embeddingModel) + ChromaVectorStore store = ChromaVectorStore.builder(this.chromaApi, this.embeddingModel) .collectionName("new-collection") .initializeSchema(true) .initializeImmediately(true) @@ -237,8 +234,7 @@ public class ChromaApiIT { @Test void shouldFailWhenCollectionDoesNotExist() { - assertThatThrownBy(() -> new ChromaVectorStore.ChromaBuilder().chromaApi(this.chromaApi) - .embeddingModel(this.embeddingModel) + assertThatThrownBy(() -> ChromaVectorStore.builder(this.chromaApi, this.embeddingModel) .collectionName("non-existent") .initializeSchema(false) .initializeImmediately(true) diff --git a/vector-stores/spring-ai-chroma-store/src/test/java/org/springframework/ai/chroma/vectorstore/ChromaVectorStoreIT.java b/vector-stores/spring-ai-chroma-store/src/test/java/org/springframework/ai/chroma/vectorstore/ChromaVectorStoreIT.java index c48c57a77..4a396a520 100644 --- a/vector-stores/spring-ai-chroma-store/src/test/java/org/springframework/ai/chroma/vectorstore/ChromaVectorStoreIT.java +++ b/vector-stores/spring-ai-chroma-store/src/test/java/org/springframework/ai/chroma/vectorstore/ChromaVectorStoreIT.java @@ -252,9 +252,7 @@ public class ChromaVectorStoreIT { @Bean public VectorStore chromaVectorStore(EmbeddingModel embeddingModel, ChromaApi chromaApi) { - return ChromaVectorStore.builder() - .chromaApi(chromaApi) - .embeddingModel(embeddingModel) + return ChromaVectorStore.builder(chromaApi, embeddingModel) .collectionName("TestCollection") .initializeSchema(true) .build(); diff --git a/vector-stores/spring-ai-chroma-store/src/test/java/org/springframework/ai/chroma/vectorstore/ChromaVectorStoreObservationIT.java b/vector-stores/spring-ai-chroma-store/src/test/java/org/springframework/ai/chroma/vectorstore/ChromaVectorStoreObservationIT.java index 22157fee4..a7ebe1913 100644 --- a/vector-stores/spring-ai-chroma-store/src/test/java/org/springframework/ai/chroma/vectorstore/ChromaVectorStoreObservationIT.java +++ b/vector-stores/spring-ai-chroma-store/src/test/java/org/springframework/ai/chroma/vectorstore/ChromaVectorStoreObservationIT.java @@ -176,9 +176,7 @@ public class ChromaVectorStoreObservationIT { @Bean public VectorStore chromaVectorStore(EmbeddingModel embeddingModel, ChromaApi chromaApi, ObservationRegistry observationRegistry) { - return ChromaVectorStore.builder() - .chromaApi(chromaApi) - .embeddingModel(embeddingModel) + return ChromaVectorStore.builder(chromaApi, embeddingModel) .collectionName("TestCollection") .initializeSchema(true) .observationRegistry(observationRegistry) diff --git a/vector-stores/spring-ai-chroma-store/src/test/java/org/springframework/ai/chroma/vectorstore/TokenSecuredChromaWhereIT.java b/vector-stores/spring-ai-chroma-store/src/test/java/org/springframework/ai/chroma/vectorstore/TokenSecuredChromaWhereIT.java index 88b5f56b8..0b0414e00 100644 --- a/vector-stores/spring-ai-chroma-store/src/test/java/org/springframework/ai/chroma/vectorstore/TokenSecuredChromaWhereIT.java +++ b/vector-stores/spring-ai-chroma-store/src/test/java/org/springframework/ai/chroma/vectorstore/TokenSecuredChromaWhereIT.java @@ -144,9 +144,7 @@ public class TokenSecuredChromaWhereIT { @Bean public VectorStore chromaVectorStore(EmbeddingModel embeddingModel, ChromaApi chromaApi) { - return ChromaVectorStore.builder() - .chromaApi(chromaApi) - .embeddingModel(embeddingModel) + return ChromaVectorStore.builder(chromaApi, embeddingModel) .collectionName("TestCollection") .initializeSchema(true) .build(); diff --git a/vector-stores/spring-ai-coherence-store/src/main/java/org/springframework/ai/vectorstore/coherence/CoherenceVectorStore.java b/vector-stores/spring-ai-coherence-store/src/main/java/org/springframework/ai/vectorstore/coherence/CoherenceVectorStore.java index 208588bed..df56d2da9 100644 --- a/vector-stores/spring-ai-coherence-store/src/main/java/org/springframework/ai/vectorstore/coherence/CoherenceVectorStore.java +++ b/vector-stores/spring-ai-coherence-store/src/main/java/org/springframework/ai/vectorstore/coherence/CoherenceVectorStore.java @@ -147,7 +147,7 @@ public class CoherenceVectorStore extends AbstractObservationVectorStore impleme */ @Deprecated(since = "1.0.0-M5", forRemoval = true) public CoherenceVectorStore(EmbeddingModel embeddingModel, Session session) { - this(builder().embeddingModel(embeddingModel).session(session)); + this(builder(session, embeddingModel)); } /** @@ -172,8 +172,8 @@ public class CoherenceVectorStore extends AbstractObservationVectorStore impleme * Creates a new builder for configuring and creating CoherenceVectorStore instances. * @return a new builder instance */ - public static CoherenceBuilder builder() { - return new CoherenceBuilder(); + public static CoherenceBuilder builder(Session session, EmbeddingModel embeddingModel) { + return new CoherenceBuilder(session, embeddingModel); } /** @@ -332,7 +332,7 @@ public class CoherenceVectorStore extends AbstractObservationVectorStore impleme */ public static class CoherenceBuilder extends AbstractVectorStoreBuilder { - private Session session; + private final Session session; private String mapName = DEFAULT_MAP_NAME; @@ -348,10 +348,10 @@ public class CoherenceVectorStore extends AbstractObservationVectorStore impleme * @return the builder instance * @throws IllegalArgumentException if session is null */ - public CoherenceBuilder session(Session session) { + public CoherenceBuilder(Session session, EmbeddingModel embeddingModel) { + super(embeddingModel); Assert.notNull(session, "Session must not be null"); this.session = session; - return this; } /** @@ -402,7 +402,6 @@ public class CoherenceVectorStore extends AbstractObservationVectorStore impleme @Override public CoherenceVectorStore build() { - validate(); return new CoherenceVectorStore(this); } diff --git a/vector-stores/spring-ai-coherence-store/src/test/java/org/springframework/ai/vectorstore/coherence/CoherenceVectorStoreIT.java b/vector-stores/spring-ai-coherence-store/src/test/java/org/springframework/ai/vectorstore/coherence/CoherenceVectorStoreIT.java index 6e8734b8c..996344ed7 100644 --- a/vector-stores/spring-ai-coherence-store/src/test/java/org/springframework/ai/vectorstore/coherence/CoherenceVectorStoreIT.java +++ b/vector-stores/spring-ai-coherence-store/src/test/java/org/springframework/ai/vectorstore/coherence/CoherenceVectorStoreIT.java @@ -311,9 +311,7 @@ public class CoherenceVectorStoreIT { @Bean public VectorStore vectorStore(EmbeddingModel embeddingModel, Session session) { - return CoherenceVectorStore.builder() - .embeddingModel(embeddingModel) - .session(session) + return CoherenceVectorStore.builder(session, embeddingModel) .distanceType(this.distanceType) .indexType(this.indexType) .forcedNormalization(this.distanceType == CoherenceVectorStore.DistanceType.COSINE diff --git a/vector-stores/spring-ai-elasticsearch-store/src/main/java/org/springframework/ai/vectorstore/elasticsearch/ElasticsearchVectorStore.java b/vector-stores/spring-ai-elasticsearch-store/src/main/java/org/springframework/ai/vectorstore/elasticsearch/ElasticsearchVectorStore.java index 52f84ad11..937dc99db 100644 --- a/vector-stores/spring-ai-elasticsearch-store/src/main/java/org/springframework/ai/vectorstore/elasticsearch/ElasticsearchVectorStore.java +++ b/vector-stores/spring-ai-elasticsearch-store/src/main/java/org/springframework/ai/vectorstore/elasticsearch/ElasticsearchVectorStore.java @@ -187,9 +187,7 @@ public class ElasticsearchVectorStore extends AbstractObservationVectorStore imp EmbeddingModel embeddingModel, boolean initializeSchema, ObservationRegistry observationRegistry, VectorStoreObservationConvention customObservationConvention, BatchingStrategy batchingStrategy) { - this(builder().restClient(restClient) - .options(options) - .embeddingModel(embeddingModel) + this(builder(restClient, embeddingModel).options(options) .initializeSchema(initializeSchema) .observationRegistry(observationRegistry) .customObservationConvention(customObservationConvention) @@ -389,13 +387,13 @@ public class ElasticsearchVectorStore extends AbstractObservationVectorStore imp * Creates a new builder instance for ElasticsearchVectorStore. * @return a new ElasticsearchBuilder instance */ - public static ElasticsearchBuilder builder() { - return new ElasticsearchBuilder(); + public static ElasticsearchBuilder builder(RestClient restClient, EmbeddingModel embeddingModel) { + return new ElasticsearchBuilder(restClient, embeddingModel); } public static class ElasticsearchBuilder extends AbstractVectorStoreBuilder { - private RestClient restClient; + private final RestClient restClient; private ElasticsearchVectorStoreOptions options = new ElasticsearchVectorStoreOptions(); @@ -411,10 +409,10 @@ public class ElasticsearchVectorStore extends AbstractObservationVectorStore imp * @return the builder instance * @throws IllegalArgumentException if restClient is null */ - public ElasticsearchBuilder restClient(RestClient restClient) { + public ElasticsearchBuilder(RestClient restClient, EmbeddingModel embeddingModel) { + super(embeddingModel); Assert.notNull(restClient, "RestClient must not be null"); this.restClient = restClient; - return this; } /** @@ -470,7 +468,6 @@ public class ElasticsearchVectorStore extends AbstractObservationVectorStore imp */ @Override public ElasticsearchVectorStore build() { - validate(); return new ElasticsearchVectorStore(this); } diff --git a/vector-stores/spring-ai-elasticsearch-store/src/test/java/org/springframework/ai/vectorstore/elasticsearch/ElasticsearchVectorStoreIT.java b/vector-stores/spring-ai-elasticsearch-store/src/test/java/org/springframework/ai/vectorstore/elasticsearch/ElasticsearchVectorStoreIT.java index 4f1de5fac..54e56bb2b 100644 --- a/vector-stores/spring-ai-elasticsearch-store/src/test/java/org/springframework/ai/vectorstore/elasticsearch/ElasticsearchVectorStoreIT.java +++ b/vector-stores/spring-ai-elasticsearch-store/src/test/java/org/springframework/ai/vectorstore/elasticsearch/ElasticsearchVectorStoreIT.java @@ -377,11 +377,7 @@ class ElasticsearchVectorStoreIT { @Bean("vectorStore_cosine") public ElasticsearchVectorStore vectorStoreDefault(EmbeddingModel embeddingModel, RestClient restClient) { - return ElasticsearchVectorStore.builder() - .restClient(restClient) - .embeddingModel(embeddingModel) - .initializeSchema(true) - .build(); + return ElasticsearchVectorStore.builder(restClient, embeddingModel).initializeSchema(true).build(); } @Bean("vectorStore_l2_norm") @@ -389,9 +385,7 @@ class ElasticsearchVectorStoreIT { ElasticsearchVectorStoreOptions options = new ElasticsearchVectorStoreOptions(); options.setIndexName("index_l2"); options.setSimilarity(SimilarityFunction.l2_norm); - return ElasticsearchVectorStore.builder() - .restClient(restClient) - .embeddingModel(embeddingModel) + return ElasticsearchVectorStore.builder(restClient, embeddingModel) .initializeSchema(true) .options(options) .build(); @@ -402,9 +396,7 @@ class ElasticsearchVectorStoreIT { ElasticsearchVectorStoreOptions options = new ElasticsearchVectorStoreOptions(); options.setIndexName("index_dot_product"); options.setSimilarity(SimilarityFunction.dot_product); - return ElasticsearchVectorStore.builder() - .restClient(restClient) - .embeddingModel(embeddingModel) + return ElasticsearchVectorStore.builder(restClient, embeddingModel) .initializeSchema(true) .options(options) .build(); diff --git a/vector-stores/spring-ai-elasticsearch-store/src/test/java/org/springframework/ai/vectorstore/elasticsearch/ElasticsearchVectorStoreObservationIT.java b/vector-stores/spring-ai-elasticsearch-store/src/test/java/org/springframework/ai/vectorstore/elasticsearch/ElasticsearchVectorStoreObservationIT.java index ae19e2ff0..77c451492 100644 --- a/vector-stores/spring-ai-elasticsearch-store/src/test/java/org/springframework/ai/vectorstore/elasticsearch/ElasticsearchVectorStoreObservationIT.java +++ b/vector-stores/spring-ai-elasticsearch-store/src/test/java/org/springframework/ai/vectorstore/elasticsearch/ElasticsearchVectorStoreObservationIT.java @@ -208,9 +208,7 @@ public class ElasticsearchVectorStoreObservationIT { @Bean public ElasticsearchVectorStore vectorStoreDefault(EmbeddingModel embeddingModel, RestClient restClient, ObservationRegistry observationRegistry) { - return ElasticsearchVectorStore.builder() - .restClient(restClient) - .embeddingModel(embeddingModel) + return ElasticsearchVectorStore.builder(restClient, embeddingModel) .initializeSchema(true) .options(new ElasticsearchVectorStoreOptions()) .observationRegistry(observationRegistry) diff --git a/vector-stores/spring-ai-gemfire-store/src/main/java/org/springframework/ai/vectorstore/gemfire/GemFireVectorStore.java b/vector-stores/spring-ai-gemfire-store/src/main/java/org/springframework/ai/vectorstore/gemfire/GemFireVectorStore.java index dbd1c9fc6..ac73a58a3 100644 --- a/vector-stores/spring-ai-gemfire-store/src/main/java/org/springframework/ai/vectorstore/gemfire/GemFireVectorStore.java +++ b/vector-stores/spring-ai-gemfire-store/src/main/java/org/springframework/ai/vectorstore/gemfire/GemFireVectorStore.java @@ -149,8 +149,7 @@ public class GemFireVectorStore extends AbstractObservationVectorStore implement ObservationRegistry observationRegistry, VectorStoreObservationConvention customObservationConvention, BatchingStrategy batchingStrategy) { - this(builder().embeddingModel(embeddingModel) - .host(config.host) + this(builder(embeddingModel).host(config.host) .port(config.port) .sslEnabled(config.sslEnabled) .indexName(config.indexName) @@ -189,8 +188,8 @@ public class GemFireVectorStore extends AbstractObservationVectorStore implement this.objectMapper = JsonMapper.builder().addModules(JacksonUtils.instantiateAvailableModules()).build(); } - public static GemFireBuilder builder() { - return new GemFireBuilder(); + public static GemFireBuilder builder(EmbeddingModel embeddingModel) { + return new GemFireBuilder(embeddingModel); } public String getIndexName() { @@ -846,6 +845,10 @@ public class GemFireVectorStore extends AbstractObservationVectorStore implement private BatchingStrategy batchingStrategy = new TokenCountBatchingStrategy(); + private GemFireBuilder(EmbeddingModel embeddingModel) { + super(embeddingModel); + } + /** * Sets the host for the GemFire connection. * @param host the host to connect to @@ -978,7 +981,6 @@ public class GemFireVectorStore extends AbstractObservationVectorStore implement @Override public GemFireVectorStore build() { - validate(); return new GemFireVectorStore(this); } diff --git a/vector-stores/spring-ai-gemfire-store/src/test/java/org/springframework/ai/vectorstore/gemfire/GemFireVectorStoreIT.java b/vector-stores/spring-ai-gemfire-store/src/test/java/org/springframework/ai/vectorstore/gemfire/GemFireVectorStoreIT.java index 8fe5bb069..a8a1b09e3 100644 --- a/vector-stores/spring-ai-gemfire-store/src/test/java/org/springframework/ai/vectorstore/gemfire/GemFireVectorStoreIT.java +++ b/vector-stores/spring-ai-gemfire-store/src/test/java/org/springframework/ai/vectorstore/gemfire/GemFireVectorStoreIT.java @@ -218,11 +218,10 @@ public class GemFireVectorStoreIT { @Bean public GemFireVectorStore vectorStore(EmbeddingModel embeddingModel) { - return GemFireVectorStore.builder() + return GemFireVectorStore.builder(embeddingModel) .host("localhost") .port(HTTP_SERVICE_PORT) .indexName(INDEX_NAME) - .embeddingModel(embeddingModel) .initializeSchema(true) .build(); } diff --git a/vector-stores/spring-ai-gemfire-store/src/test/java/org/springframework/ai/vectorstore/gemfire/GemFireVectorStoreObservationIT.java b/vector-stores/spring-ai-gemfire-store/src/test/java/org/springframework/ai/vectorstore/gemfire/GemFireVectorStoreObservationIT.java index b3f17e092..4fcf24763 100644 --- a/vector-stores/spring-ai-gemfire-store/src/test/java/org/springframework/ai/vectorstore/gemfire/GemFireVectorStoreObservationIT.java +++ b/vector-stores/spring-ai-gemfire-store/src/test/java/org/springframework/ai/vectorstore/gemfire/GemFireVectorStoreObservationIT.java @@ -200,11 +200,10 @@ public class GemFireVectorStoreObservationIT { @Bean public GemFireVectorStore vectorStore(EmbeddingModel embeddingModel, ObservationRegistry observationRegistry) { - return GemFireVectorStore.builder() + return GemFireVectorStore.builder(embeddingModel) .host("localhost") .port(HTTP_SERVICE_PORT) .indexName(TEST_INDEX_NAME) - .embeddingModel(embeddingModel) .initializeSchema(true) .observationRegistry(observationRegistry) .customObservationConvention(null) diff --git a/vector-stores/spring-ai-hanadb-store/src/main/java/org/springframework/ai/vectorstore/hanadb/HanaCloudVectorStore.java b/vector-stores/spring-ai-hanadb-store/src/main/java/org/springframework/ai/vectorstore/hanadb/HanaCloudVectorStore.java index 51d8bb083..685ffb35f 100644 --- a/vector-stores/spring-ai-hanadb-store/src/main/java/org/springframework/ai/vectorstore/hanadb/HanaCloudVectorStore.java +++ b/vector-stores/spring-ai-hanadb-store/src/main/java/org/springframework/ai/vectorstore/hanadb/HanaCloudVectorStore.java @@ -115,9 +115,7 @@ public class HanaCloudVectorStore extends AbstractObservationVectorStore { EmbeddingModel embeddingModel, HanaCloudVectorStoreConfig config, ObservationRegistry observationRegistry, VectorStoreObservationConvention customObservationConvention) { - this(builder().repository(repository) - .embeddingModel(embeddingModel) - .tableName(config.getTableName()) + this(builder(repository, embeddingModel).tableName(config.getTableName()) .topK(config.getTopK()) .observationRegistry(observationRegistry) .customObservationConvention(customObservationConvention)); @@ -143,8 +141,9 @@ public class HanaCloudVectorStore extends AbstractObservationVectorStore { * Creates a new builder for configuring and creating HanaCloudVectorStore instances. * @return a new builder instance */ - public static HanaCloudBuilder builder() { - return new HanaCloudBuilder(); + public static HanaCloudBuilder builder(HanaVectorRepository repository, + EmbeddingModel embeddingModel) { + return new HanaCloudBuilder(repository, embeddingModel); } @Override @@ -233,7 +232,7 @@ public class HanaCloudVectorStore extends AbstractObservationVectorStore { */ public static class HanaCloudBuilder extends AbstractVectorStoreBuilder { - private HanaVectorRepository repository; + private final HanaVectorRepository repository; private String tableName; @@ -245,10 +244,11 @@ public class HanaCloudVectorStore extends AbstractObservationVectorStore { * @return the builder instance * @throws IllegalArgumentException if repository is null */ - public HanaCloudBuilder repository(HanaVectorRepository repository) { + public HanaCloudBuilder(HanaVectorRepository repository, + EmbeddingModel embeddingModel) { + super(embeddingModel); Assert.notNull(repository, "Repository must not be null"); this.repository = repository; - return this; } /** @@ -273,7 +273,6 @@ public class HanaCloudVectorStore extends AbstractObservationVectorStore { @Override public HanaCloudVectorStore build() { - validate(); return new HanaCloudVectorStore(this); } diff --git a/vector-stores/spring-ai-hanadb-store/src/test/java/org/springframework/ai/vectorstore/hanadb/HanaCloudVectorStoreIT.java b/vector-stores/spring-ai-hanadb-store/src/test/java/org/springframework/ai/vectorstore/hanadb/HanaCloudVectorStoreIT.java index 7015c31b6..6a4131f34 100644 --- a/vector-stores/spring-ai-hanadb-store/src/test/java/org/springframework/ai/vectorstore/hanadb/HanaCloudVectorStoreIT.java +++ b/vector-stores/spring-ai-hanadb-store/src/test/java/org/springframework/ai/vectorstore/hanadb/HanaCloudVectorStoreIT.java @@ -91,9 +91,7 @@ public class HanaCloudVectorStoreIT { public VectorStore hanaCloudVectorStore(CricketWorldCupRepository cricketWorldCupRepository, EmbeddingModel embeddingModel) { - return HanaCloudVectorStore.builder() - .repository(cricketWorldCupRepository) - .embeddingModel(embeddingModel) + return HanaCloudVectorStore.builder(cricketWorldCupRepository, embeddingModel) .tableName("CRICKET_WORLD_CUP") .topK(1) .build(); diff --git a/vector-stores/spring-ai-hanadb-store/src/test/java/org/springframework/ai/vectorstore/hanadb/HanaVectorStoreObservationIT.java b/vector-stores/spring-ai-hanadb-store/src/test/java/org/springframework/ai/vectorstore/hanadb/HanaVectorStoreObservationIT.java index d537aec42..a37d5af13 100644 --- a/vector-stores/spring-ai-hanadb-store/src/test/java/org/springframework/ai/vectorstore/hanadb/HanaVectorStoreObservationIT.java +++ b/vector-stores/spring-ai-hanadb-store/src/test/java/org/springframework/ai/vectorstore/hanadb/HanaVectorStoreObservationIT.java @@ -167,9 +167,7 @@ public class HanaVectorStoreObservationIT { public VectorStore hanaCloudVectorStore(CricketWorldCupRepository cricketWorldCupRepository, EmbeddingModel embeddingModel, ObservationRegistry observationRegistry) { - return HanaCloudVectorStore.builder() - .repository(cricketWorldCupRepository) - .embeddingModel(embeddingModel) + return HanaCloudVectorStore.builder(cricketWorldCupRepository, embeddingModel) .tableName(TEST_TABLE_NAME) .topK(1) .observationRegistry(observationRegistry) diff --git a/vector-stores/spring-ai-mariadb-store/src/main/java/org/springframework/ai/vectorstore/mariadb/MariaDBVectorStore.java b/vector-stores/spring-ai-mariadb-store/src/main/java/org/springframework/ai/vectorstore/mariadb/MariaDBVectorStore.java index e801c3ad5..10e3c5b3d 100644 --- a/vector-stores/spring-ai-mariadb-store/src/main/java/org/springframework/ai/vectorstore/mariadb/MariaDBVectorStore.java +++ b/vector-stores/spring-ai-mariadb-store/src/main/java/org/springframework/ai/vectorstore/mariadb/MariaDBVectorStore.java @@ -256,8 +256,7 @@ public class MariaDBVectorStore extends AbstractObservationVectorStore implement int maxDocumentBatchSize, String contentFieldName, String embeddingFieldName, String idFieldName, String metadataFieldName) { - this(builder(jdbcTemplate).vectorTableName(vectorTableName) - .embeddingModel(embeddingModel) + this(builder(jdbcTemplate, embeddingModel).vectorTableName(vectorTableName) .dimensions(dimensions) .distanceType(distanceType) .removeExistingVectorStoreTable(removeExistingVectorStoreTable) @@ -319,8 +318,8 @@ public class MariaDBVectorStore extends AbstractObservationVectorStore implement * MariaDBVectorStore. * @return a new MariaDBBuilder instance */ - public static MariaDBBuilder builder(JdbcTemplate jdbcTemplate) { - return new MariaDBBuilder(jdbcTemplate); + public static MariaDBBuilder builder(JdbcTemplate jdbcTemplate, EmbeddingModel embeddingModel) { + return new MariaDBBuilder(jdbcTemplate, embeddingModel); } public MariaDBDistanceType getDistanceType() { @@ -595,7 +594,8 @@ public class MariaDBVectorStore extends AbstractObservationVectorStore implement * @param jdbcTemplate the JDBC template for database operations * @throws IllegalArgumentException if jdbcTemplate is null */ - MariaDBBuilder(JdbcTemplate jdbcTemplate) { + private MariaDBBuilder(JdbcTemplate jdbcTemplate, EmbeddingModel embeddingModel) { + super(embeddingModel); Assert.notNull(jdbcTemplate, "JdbcTemplate must not be null"); this.jdbcTemplate = jdbcTemplate; } @@ -758,7 +758,6 @@ public class MariaDBVectorStore extends AbstractObservationVectorStore implement */ @Override public MariaDBVectorStore build() { - validate(); return new MariaDBVectorStore(this); } diff --git a/vector-stores/spring-ai-mariadb-store/src/test/java/org/springframework/ai/vectorstore/mariadb/MariaDBEmbeddingDimensionsTests.java b/vector-stores/spring-ai-mariadb-store/src/test/java/org/springframework/ai/vectorstore/mariadb/MariaDBEmbeddingDimensionsTests.java index c57f8e676..2e7ec9abe 100644 --- a/vector-stores/spring-ai-mariadb-store/src/test/java/org/springframework/ai/vectorstore/mariadb/MariaDBEmbeddingDimensionsTests.java +++ b/vector-stores/spring-ai-mariadb-store/src/test/java/org/springframework/ai/vectorstore/mariadb/MariaDBEmbeddingDimensionsTests.java @@ -47,8 +47,7 @@ public class MariaDBEmbeddingDimensionsTests { final int explicitDimensions = 696; - MariaDBVectorStore mariaDBVectorStore = MariaDBVectorStore.builder(this.jdbcTemplate) - .embeddingModel(this.embeddingModel) + MariaDBVectorStore mariaDBVectorStore = MariaDBVectorStore.builder(this.jdbcTemplate, this.embeddingModel) .dimensions(explicitDimensions) .build(); var dim = mariaDBVectorStore.embeddingDimensions(); @@ -61,8 +60,7 @@ public class MariaDBEmbeddingDimensionsTests { public void embeddingModelDimensions() { when(this.embeddingModel.dimensions()).thenReturn(969); - MariaDBVectorStore mariaDBVectorStore = MariaDBVectorStore.builder(this.jdbcTemplate) - .embeddingModel(this.embeddingModel) + MariaDBVectorStore mariaDBVectorStore = MariaDBVectorStore.builder(this.jdbcTemplate, this.embeddingModel) .build(); var dim = mariaDBVectorStore.embeddingDimensions(); @@ -76,8 +74,7 @@ public class MariaDBEmbeddingDimensionsTests { when(this.embeddingModel.dimensions()).thenThrow(new RuntimeException()); - MariaDBVectorStore mariaDBVectorStore = MariaDBVectorStore.builder(this.jdbcTemplate) - .embeddingModel(this.embeddingModel) + MariaDBVectorStore mariaDBVectorStore = MariaDBVectorStore.builder(this.jdbcTemplate, this.embeddingModel) .build(); var dim = mariaDBVectorStore.embeddingDimensions(); diff --git a/vector-stores/spring-ai-mariadb-store/src/test/java/org/springframework/ai/vectorstore/mariadb/MariaDBStoreCustomNamesIT.java b/vector-stores/spring-ai-mariadb-store/src/test/java/org/springframework/ai/vectorstore/mariadb/MariaDBStoreCustomNamesIT.java index 3f60e501e..7c24948b2 100644 --- a/vector-stores/spring-ai-mariadb-store/src/test/java/org/springframework/ai/vectorstore/mariadb/MariaDBStoreCustomNamesIT.java +++ b/vector-stores/spring-ai-mariadb-store/src/test/java/org/springframework/ai/vectorstore/mariadb/MariaDBStoreCustomNamesIT.java @@ -217,8 +217,7 @@ public class MariaDBStoreCustomNamesIT { @Bean public VectorStore vectorStore(JdbcTemplate jdbcTemplate, EmbeddingModel embeddingModel) { - return MariaDBVectorStore.builder(jdbcTemplate) - .embeddingModel(embeddingModel) + return MariaDBVectorStore.builder(jdbcTemplate, embeddingModel) .schemaName(this.schemaName) .vectorTableName(this.vectorTableName) .schemaValidation(this.schemaValidation) diff --git a/vector-stores/spring-ai-mariadb-store/src/test/java/org/springframework/ai/vectorstore/mariadb/MariaDBStoreIT.java b/vector-stores/spring-ai-mariadb-store/src/test/java/org/springframework/ai/vectorstore/mariadb/MariaDBStoreIT.java index 54ab39ab9..8a1431140 100644 --- a/vector-stores/spring-ai-mariadb-store/src/test/java/org/springframework/ai/vectorstore/mariadb/MariaDBStoreIT.java +++ b/vector-stores/spring-ai-mariadb-store/src/test/java/org/springframework/ai/vectorstore/mariadb/MariaDBStoreIT.java @@ -347,8 +347,7 @@ public class MariaDBStoreIT { @Bean public VectorStore vectorStore(JdbcTemplate jdbcTemplate, EmbeddingModel embeddingModel) { - return MariaDBVectorStore.builder(jdbcTemplate) - .embeddingModel(embeddingModel) + return MariaDBVectorStore.builder(jdbcTemplate, embeddingModel) .dimensions(MariaDBVectorStore.INVALID_EMBEDDING_DIMENSION) .distanceType(this.distanceType) .removeExistingVectorStoreTable(true) diff --git a/vector-stores/spring-ai-mariadb-store/src/test/java/org/springframework/ai/vectorstore/mariadb/MariaDBStoreObservationIT.java b/vector-stores/spring-ai-mariadb-store/src/test/java/org/springframework/ai/vectorstore/mariadb/MariaDBStoreObservationIT.java index 2e183bc52..caca46eea 100644 --- a/vector-stores/spring-ai-mariadb-store/src/test/java/org/springframework/ai/vectorstore/mariadb/MariaDBStoreObservationIT.java +++ b/vector-stores/spring-ai-mariadb-store/src/test/java/org/springframework/ai/vectorstore/mariadb/MariaDBStoreObservationIT.java @@ -177,8 +177,7 @@ public class MariaDBStoreObservationIT { @Bean public VectorStore vectorStore(JdbcTemplate jdbcTemplate, EmbeddingModel embeddingModel, ObservationRegistry observationRegistry) { - return MariaDBVectorStore.builder(jdbcTemplate) - .embeddingModel(embeddingModel) + return MariaDBVectorStore.builder(jdbcTemplate, embeddingModel) .schemaName(schemaName) .distanceType(MariaDBVectorStore.MariaDBDistanceType.COSINE) .observationRegistry(observationRegistry) diff --git a/vector-stores/spring-ai-mariadb-store/src/test/java/org/springframework/ai/vectorstore/mariadb/MariaDBStoreTests.java b/vector-stores/spring-ai-mariadb-store/src/test/java/org/springframework/ai/vectorstore/mariadb/MariaDBStoreTests.java index defe99548..be36e0792 100644 --- a/vector-stores/spring-ai-mariadb-store/src/test/java/org/springframework/ai/vectorstore/mariadb/MariaDBStoreTests.java +++ b/vector-stores/spring-ai-mariadb-store/src/test/java/org/springframework/ai/vectorstore/mariadb/MariaDBStoreTests.java @@ -70,8 +70,7 @@ public class MariaDBStoreTests { // Given var jdbcTemplate = mock(JdbcTemplate.class); var embeddingModel = mock(EmbeddingModel.class); - var mariadbVectorStore = MariaDBVectorStore.builder(jdbcTemplate) - .embeddingModel(embeddingModel) + var mariadbVectorStore = MariaDBVectorStore.builder(jdbcTemplate, embeddingModel) .maxDocumentBatchSize(1000) .build(); diff --git a/vector-stores/spring-ai-mariadb-store/src/test/java/org/springframework/ai/vectorstore/mariadb/MariaDBVectorStoreBuilderTests.java b/vector-stores/spring-ai-mariadb-store/src/test/java/org/springframework/ai/vectorstore/mariadb/MariaDBVectorStoreBuilderTests.java index 4e0e1eeb7..ed28a7f25 100644 --- a/vector-stores/spring-ai-mariadb-store/src/test/java/org/springframework/ai/vectorstore/mariadb/MariaDBVectorStoreBuilderTests.java +++ b/vector-stores/spring-ai-mariadb-store/src/test/java/org/springframework/ai/vectorstore/mariadb/MariaDBVectorStoreBuilderTests.java @@ -38,22 +38,21 @@ class MariaDBVectorStoreBuilderTests { @Test void shouldFailOnMissingEmbeddingModel() { - assertThatThrownBy(() -> MariaDBVectorStore.builder(jdbcTemplate).build()) + assertThatThrownBy(() -> MariaDBVectorStore.builder(jdbcTemplate, null).build()) .isInstanceOf(IllegalArgumentException.class) .hasMessageContaining("EmbeddingModel must be configured"); } @Test void shouldFailOnMissingJdbcTemplate() { - assertThatThrownBy(() -> MariaDBVectorStore.builder(null).build()).isInstanceOf(IllegalArgumentException.class) + assertThatThrownBy(() -> MariaDBVectorStore.builder(null, embeddingModel).build()) + .isInstanceOf(IllegalArgumentException.class) .hasMessageContaining("JdbcTemplate must not be null"); } @Test void shouldUseDefaultValues() { - MariaDBVectorStore vectorStore = MariaDBVectorStore.builder(jdbcTemplate) - .embeddingModel(embeddingModel) - .build(); + MariaDBVectorStore vectorStore = MariaDBVectorStore.builder(jdbcTemplate, embeddingModel).build(); assertThat(vectorStore).hasFieldOrPropertyWithValue("vectorTableName", "vector_store") .hasFieldOrPropertyWithValue("schemaName", null) @@ -71,8 +70,7 @@ class MariaDBVectorStoreBuilderTests { @Test void shouldConfigureCustomValues() { - MariaDBVectorStore vectorStore = MariaDBVectorStore.builder(jdbcTemplate) - .embeddingModel(embeddingModel) + MariaDBVectorStore vectorStore = MariaDBVectorStore.builder(jdbcTemplate, embeddingModel) .schemaName("custom_schema") .vectorTableName("custom_vectors") .schemaValidation(true) @@ -103,60 +101,49 @@ class MariaDBVectorStoreBuilderTests { @Test void shouldValidateFieldNames() { - assertThatThrownBy(() -> MariaDBVectorStore.builder(jdbcTemplate) - .embeddingModel(embeddingModel) - .contentFieldName("") - .build()).isInstanceOf(IllegalArgumentException.class) + assertThatThrownBy(() -> MariaDBVectorStore.builder(jdbcTemplate, embeddingModel).contentFieldName("").build()) + .isInstanceOf(IllegalArgumentException.class) .hasMessageContaining("ContentFieldName must not be empty"); - assertThatThrownBy(() -> MariaDBVectorStore.builder(jdbcTemplate) - .embeddingModel(embeddingModel) - .embeddingFieldName("") - .build()).isInstanceOf(IllegalArgumentException.class) + assertThatThrownBy( + () -> MariaDBVectorStore.builder(jdbcTemplate, embeddingModel).embeddingFieldName("").build()) + .isInstanceOf(IllegalArgumentException.class) .hasMessageContaining("EmbeddingFieldName must not be empty"); - assertThatThrownBy( - () -> MariaDBVectorStore.builder(jdbcTemplate).embeddingModel(embeddingModel).idFieldName("").build()) + assertThatThrownBy(() -> MariaDBVectorStore.builder(jdbcTemplate, embeddingModel).idFieldName("").build()) .isInstanceOf(IllegalArgumentException.class) .hasMessageContaining("IdFieldName must not be empty"); - assertThatThrownBy(() -> MariaDBVectorStore.builder(jdbcTemplate) - .embeddingModel(embeddingModel) - .metadataFieldName("") - .build()).isInstanceOf(IllegalArgumentException.class) + assertThatThrownBy(() -> MariaDBVectorStore.builder(jdbcTemplate, embeddingModel).metadataFieldName("").build()) + .isInstanceOf(IllegalArgumentException.class) .hasMessageContaining("MetadataFieldName must not be empty"); } @Test void shouldValidateMaxDocumentBatchSize() { - assertThatThrownBy(() -> MariaDBVectorStore.builder(jdbcTemplate) - .embeddingModel(embeddingModel) - .maxDocumentBatchSize(0) - .build()).isInstanceOf(IllegalArgumentException.class) + assertThatThrownBy( + () -> MariaDBVectorStore.builder(jdbcTemplate, embeddingModel).maxDocumentBatchSize(0).build()) + .isInstanceOf(IllegalArgumentException.class) .hasMessageContaining("MaxDocumentBatchSize must be positive"); - assertThatThrownBy(() -> MariaDBVectorStore.builder(jdbcTemplate) - .embeddingModel(embeddingModel) - .maxDocumentBatchSize(-1) - .build()).isInstanceOf(IllegalArgumentException.class) + assertThatThrownBy( + () -> MariaDBVectorStore.builder(jdbcTemplate, embeddingModel).maxDocumentBatchSize(-1).build()) + .isInstanceOf(IllegalArgumentException.class) .hasMessageContaining("MaxDocumentBatchSize must be positive"); } @Test void shouldValidateDistanceType() { - assertThatThrownBy(() -> MariaDBVectorStore.builder(jdbcTemplate) - .embeddingModel(embeddingModel) - .distanceType(null) - .build()).isInstanceOf(IllegalArgumentException.class) + assertThatThrownBy(() -> MariaDBVectorStore.builder(jdbcTemplate, embeddingModel).distanceType(null).build()) + .isInstanceOf(IllegalArgumentException.class) .hasMessageContaining("DistanceType must not be null"); } @Test void shouldValidateBatchingStrategy() { - assertThatThrownBy(() -> MariaDBVectorStore.builder(jdbcTemplate) - .embeddingModel(embeddingModel) - .batchingStrategy(null) - .build()).isInstanceOf(IllegalArgumentException.class) + assertThatThrownBy( + () -> MariaDBVectorStore.builder(jdbcTemplate, embeddingModel).batchingStrategy(null).build()) + .isInstanceOf(IllegalArgumentException.class) .hasMessageContaining("BatchingStrategy must not be null"); } diff --git a/vector-stores/spring-ai-milvus-store/src/main/java/org/springframework/ai/milvus/vectorstore/MilvusVectorStore.java b/vector-stores/spring-ai-milvus-store/src/main/java/org/springframework/ai/milvus/vectorstore/MilvusVectorStore.java index 7976b31bb..dd1bf72a6 100644 --- a/vector-stores/spring-ai-milvus-store/src/main/java/org/springframework/ai/milvus/vectorstore/MilvusVectorStore.java +++ b/vector-stores/spring-ai-milvus-store/src/main/java/org/springframework/ai/milvus/vectorstore/MilvusVectorStore.java @@ -230,9 +230,7 @@ public class MilvusVectorStore extends AbstractObservationVectorStore implements MilvusVectorStoreConfig config, boolean initializeSchema, BatchingStrategy batchingStrategy, ObservationRegistry observationRegistry, VectorStoreObservationConvention customObservationConvention) { - this(builder().milvusClient(milvusClient) - .embeddingModel(embeddingModel) - .observationRegistry(observationRegistry) + this(builder(milvusClient, embeddingModel).observationRegistry(observationRegistry) .customObservationConvention(customObservationConvention) .initializeSchema(initializeSchema) .batchingStrategy(batchingStrategy)); @@ -268,8 +266,8 @@ public class MilvusVectorStore extends AbstractObservationVectorStore implements * recommended way to instantiate a MilvusBuilder. * @return a new MilvusBuilder instance */ - public static MilvusBuilder builder() { - return new MilvusBuilder(); + public static MilvusBuilder builder(MilvusServiceClient milvusClient, EmbeddingModel embeddingModel) { + return new MilvusBuilder(milvusClient, embeddingModel); } @Override @@ -579,6 +577,8 @@ public class MilvusVectorStore extends AbstractObservationVectorStore implements public static final class MilvusBuilder extends AbstractVectorStoreBuilder { + private final MilvusServiceClient milvusClient; + private String databaseName = DEFAULT_DATABASE_NAME; private String collectionName = DEFAULT_COLLECTION_NAME; @@ -603,18 +603,16 @@ public class MilvusVectorStore extends AbstractObservationVectorStore implements private boolean initializeSchema = false; - private MilvusServiceClient milvusClient; - private BatchingStrategy batchingStrategy = new TokenCountBatchingStrategy(); /** * @param milvusClient the Milvus service client to use for database operations * @throws IllegalArgumentException if milvusClient is null */ - public MilvusBuilder milvusClient(MilvusServiceClient milvusClient) { + private MilvusBuilder(MilvusServiceClient milvusClient, EmbeddingModel embeddingModel) { + super(embeddingModel); Assert.notNull(milvusClient, "milvusClient must not be null"); this.milvusClient = milvusClient; - return this; } /** @@ -773,7 +771,6 @@ public class MilvusVectorStore extends AbstractObservationVectorStore implements * @throws IllegalStateException if the builder configuration is invalid */ public MilvusVectorStore build() { - validate(); return new MilvusVectorStore(this); } diff --git a/vector-stores/spring-ai-milvus-store/src/test/java/org/springframework/ai/milvus/vectorstore/MilvusEmbeddingDimensionsTests.java b/vector-stores/spring-ai-milvus-store/src/test/java/org/springframework/ai/milvus/vectorstore/MilvusEmbeddingDimensionsTests.java index 32cb665e9..86315749b 100644 --- a/vector-stores/spring-ai-milvus-store/src/test/java/org/springframework/ai/milvus/vectorstore/MilvusEmbeddingDimensionsTests.java +++ b/vector-stores/spring-ai-milvus-store/src/test/java/org/springframework/ai/milvus/vectorstore/MilvusEmbeddingDimensionsTests.java @@ -53,9 +53,7 @@ public class MilvusEmbeddingDimensionsTests { final int explicitDimensions = 696; - MilvusVectorStore build = MilvusVectorStore.builder() - .milvusClient(this.milvusClient) - .embeddingModel(this.embeddingModel) + MilvusVectorStore build = MilvusVectorStore.builder(this.milvusClient, this.embeddingModel) .initializeSchema(true) .batchingStrategy(new TokenCountBatchingStrategy()) .embeddingDimension(explicitDimensions) @@ -70,9 +68,7 @@ public class MilvusEmbeddingDimensionsTests { public void embeddingModelDimensions() { given(this.embeddingModel.dimensions()).willReturn(969); - MilvusVectorStore build = MilvusVectorStore.builder() - .milvusClient(this.milvusClient) - .embeddingModel(this.embeddingModel) + MilvusVectorStore build = MilvusVectorStore.builder(this.milvusClient, this.embeddingModel) .initializeSchema(true) .batchingStrategy(new TokenCountBatchingStrategy()) .build(); @@ -88,9 +84,7 @@ public class MilvusEmbeddingDimensionsTests { given(this.embeddingModel.dimensions()).willThrow(new RuntimeException()); - MilvusVectorStore build = MilvusVectorStore.builder() - .milvusClient(this.milvusClient) - .embeddingModel(this.embeddingModel) + MilvusVectorStore build = MilvusVectorStore.builder(this.milvusClient, this.embeddingModel) .initializeSchema(true) .batchingStrategy(new TokenCountBatchingStrategy()) .build(); @@ -104,8 +98,8 @@ public class MilvusEmbeddingDimensionsTests { @ValueSource(ints = { 0, 32769 }) public void invalidDimensionsThrowException(final int explicitDimensions) { // when - ThrowableAssert.ThrowingCallable actual = () -> MilvusVectorStore.builder() - .milvusClient(this.milvusClient) + ThrowableAssert.ThrowingCallable actual = () -> MilvusVectorStore + .builder(this.milvusClient, this.embeddingModel) .embeddingDimension(explicitDimensions) .build(); diff --git a/vector-stores/spring-ai-milvus-store/src/test/java/org/springframework/ai/milvus/vectorstore/MilvusVectorStoreCustomFieldNamesIT.java b/vector-stores/spring-ai-milvus-store/src/test/java/org/springframework/ai/milvus/vectorstore/MilvusVectorStoreCustomFieldNamesIT.java index 0934fcc3c..cc6eddbe1 100644 --- a/vector-stores/spring-ai-milvus-store/src/test/java/org/springframework/ai/milvus/vectorstore/MilvusVectorStoreCustomFieldNamesIT.java +++ b/vector-stores/spring-ai-milvus-store/src/test/java/org/springframework/ai/milvus/vectorstore/MilvusVectorStoreCustomFieldNamesIT.java @@ -230,9 +230,7 @@ class MilvusVectorStoreCustomFieldNamesIT { @Bean VectorStore vectorStore(MilvusServiceClient milvusClient, EmbeddingModel embeddingModel) { - return MilvusVectorStore.builder() - .milvusClient(milvusClient) - .embeddingModel(embeddingModel) + return MilvusVectorStore.builder(milvusClient, embeddingModel) .collectionName("test_vector_store_custom_fields") .databaseName("default") .indexType(IndexType.IVF_FLAT) diff --git a/vector-stores/spring-ai-milvus-store/src/test/java/org/springframework/ai/milvus/vectorstore/MilvusVectorStoreIT.java b/vector-stores/spring-ai-milvus-store/src/test/java/org/springframework/ai/milvus/vectorstore/MilvusVectorStoreIT.java index b3f08670a..18cd23f57 100644 --- a/vector-stores/spring-ai-milvus-store/src/test/java/org/springframework/ai/milvus/vectorstore/MilvusVectorStoreIT.java +++ b/vector-stores/spring-ai-milvus-store/src/test/java/org/springframework/ai/milvus/vectorstore/MilvusVectorStoreIT.java @@ -269,9 +269,7 @@ public class MilvusVectorStoreIT { @Bean public VectorStore vectorStore(MilvusServiceClient milvusClient, EmbeddingModel embeddingModel) { - return MilvusVectorStore.builder() - .milvusClient(milvusClient) - .embeddingModel(embeddingModel) + return MilvusVectorStore.builder(milvusClient, embeddingModel) .collectionName("test_vector_store") .databaseName("default") .indexType(IndexType.IVF_FLAT) diff --git a/vector-stores/spring-ai-milvus-store/src/test/java/org/springframework/ai/milvus/vectorstore/MilvusVectorStoreObservationIT.java b/vector-stores/spring-ai-milvus-store/src/test/java/org/springframework/ai/milvus/vectorstore/MilvusVectorStoreObservationIT.java index 1df3ac1ae..89e4df509 100644 --- a/vector-stores/spring-ai-milvus-store/src/test/java/org/springframework/ai/milvus/vectorstore/MilvusVectorStoreObservationIT.java +++ b/vector-stores/spring-ai-milvus-store/src/test/java/org/springframework/ai/milvus/vectorstore/MilvusVectorStoreObservationIT.java @@ -170,9 +170,7 @@ public class MilvusVectorStoreObservationIT { @Bean public VectorStore vectorStore(MilvusServiceClient milvusClient, EmbeddingModel embeddingModel, ObservationRegistry observationRegistry) { - return MilvusVectorStore.builder() - .milvusClient(milvusClient) - .embeddingModel(embeddingModel) + return MilvusVectorStore.builder(milvusClient, embeddingModel) .observationRegistry(observationRegistry) .collectionName(TEST_COLLECTION_NAME) .databaseName("default") diff --git a/vector-stores/spring-ai-mongodb-atlas-store/src/main/java/org/springframework/ai/vectorstore/mongodb/atlas/MongoDBAtlasVectorStore.java b/vector-stores/spring-ai-mongodb-atlas-store/src/main/java/org/springframework/ai/vectorstore/mongodb/atlas/MongoDBAtlasVectorStore.java index 067a7292d..65ce0957b 100644 --- a/vector-stores/spring-ai-mongodb-atlas-store/src/main/java/org/springframework/ai/vectorstore/mongodb/atlas/MongoDBAtlasVectorStore.java +++ b/vector-stores/spring-ai-mongodb-atlas-store/src/main/java/org/springframework/ai/vectorstore/mongodb/atlas/MongoDBAtlasVectorStore.java @@ -187,9 +187,7 @@ public class MongoDBAtlasVectorStore extends AbstractObservationVectorStore impl MongoDBVectorStoreConfig config, boolean initializeSchema, ObservationRegistry observationRegistry, VectorStoreObservationConvention customObservationConvention, BatchingStrategy batchingStrategy) { - this(builder().mongoTemplate(mongoTemplate) - .embeddingModel(embeddingModel) - .collectionName(config.collectionName) + this(builder(mongoTemplate, embeddingModel).collectionName(config.collectionName) .vectorIndexName(config.vectorIndexName) .pathName(config.pathName) .numCandidates(config.numCandidates) @@ -354,13 +352,13 @@ public class MongoDBAtlasVectorStore extends AbstractObservationVectorStore impl * Creates a new builder instance for MongoDBAtlasVectorStore. * @return a new MongoDBBuilder instance */ - public static MongoDBBuilder builder() { - return new MongoDBBuilder(); + public static MongoDBBuilder builder(MongoTemplate mongoTemplate, EmbeddingModel embeddingModel) { + return new MongoDBBuilder(mongoTemplate, embeddingModel); } public static class MongoDBBuilder extends AbstractVectorStoreBuilder { - private MongoTemplate mongoTemplate; + private final MongoTemplate mongoTemplate; private String collectionName = DEFAULT_VECTOR_COLLECTION_NAME; @@ -381,10 +379,10 @@ public class MongoDBAtlasVectorStore extends AbstractObservationVectorStore impl /** * @throws IllegalArgumentException if mongoTemplate is null */ - public MongoDBBuilder mongoTemplate(MongoTemplate mongoTemplate) { + public MongoDBBuilder(MongoTemplate mongoTemplate, EmbeddingModel embeddingModel) { + super(embeddingModel); Assert.notNull(mongoTemplate, "MongoTemplate must not be null"); this.mongoTemplate = mongoTemplate; - return this; } /** @@ -489,7 +487,6 @@ public class MongoDBAtlasVectorStore extends AbstractObservationVectorStore impl */ @Override public MongoDBAtlasVectorStore build() { - validate(); return new MongoDBAtlasVectorStore(this); } diff --git a/vector-stores/spring-ai-mongodb-atlas-store/src/test/java/org/springframework/ai/vectorstore/mongodb/atlas/MongoDBAtlasVectorStoreIT.java b/vector-stores/spring-ai-mongodb-atlas-store/src/test/java/org/springframework/ai/vectorstore/mongodb/atlas/MongoDBAtlasVectorStoreIT.java index 9152a2752..9c332e66a 100644 --- a/vector-stores/spring-ai-mongodb-atlas-store/src/test/java/org/springframework/ai/vectorstore/mongodb/atlas/MongoDBAtlasVectorStoreIT.java +++ b/vector-stores/spring-ai-mongodb-atlas-store/src/test/java/org/springframework/ai/vectorstore/mongodb/atlas/MongoDBAtlasVectorStoreIT.java @@ -259,9 +259,7 @@ class MongoDBAtlasVectorStoreIT { @Bean public VectorStore vectorStore(MongoTemplate mongoTemplate, EmbeddingModel embeddingModel) { - return MongoDBAtlasVectorStore.builder() - .mongoTemplate(mongoTemplate) - .embeddingModel(embeddingModel) + return MongoDBAtlasVectorStore.builder(mongoTemplate, embeddingModel) .metadataFieldsToFilter(List.of("country", "year")) .initializeSchema(true) .build(); diff --git a/vector-stores/spring-ai-mongodb-atlas-store/src/test/java/org/springframework/ai/vectorstore/mongodb/atlas/MongoDbVectorStoreObservationIT.java b/vector-stores/spring-ai-mongodb-atlas-store/src/test/java/org/springframework/ai/vectorstore/mongodb/atlas/MongoDbVectorStoreObservationIT.java index 7a83cbf90..38f1ad88e 100644 --- a/vector-stores/spring-ai-mongodb-atlas-store/src/test/java/org/springframework/ai/vectorstore/mongodb/atlas/MongoDbVectorStoreObservationIT.java +++ b/vector-stores/spring-ai-mongodb-atlas-store/src/test/java/org/springframework/ai/vectorstore/mongodb/atlas/MongoDbVectorStoreObservationIT.java @@ -187,9 +187,7 @@ public class MongoDbVectorStoreObservationIT { @Bean public VectorStore vectorStore(MongoTemplate mongoTemplate, EmbeddingModel embeddingModel, ObservationRegistry observationRegistry) { - return MongoDBAtlasVectorStore.builder() - .mongoTemplate(mongoTemplate) - .embeddingModel(embeddingModel) + return MongoDBAtlasVectorStore.builder(mongoTemplate, embeddingModel) .metadataFieldsToFilter(List.of("country", "year")) .initializeSchema(true) .observationRegistry(observationRegistry) diff --git a/vector-stores/spring-ai-neo4j-store/src/main/java/org/springframework/ai/vectorstore/neo4j/Neo4jVectorStore.java b/vector-stores/spring-ai-neo4j-store/src/main/java/org/springframework/ai/vectorstore/neo4j/Neo4jVectorStore.java index b91278405..75108e37c 100644 --- a/vector-stores/spring-ai-neo4j-store/src/main/java/org/springframework/ai/vectorstore/neo4j/Neo4jVectorStore.java +++ b/vector-stores/spring-ai-neo4j-store/src/main/java/org/springframework/ai/vectorstore/neo4j/Neo4jVectorStore.java @@ -196,9 +196,7 @@ public class Neo4jVectorStore extends AbstractObservationVectorStore implements boolean initializeSchema, ObservationRegistry observationRegistry, VectorStoreObservationConvention customObservationConvention, BatchingStrategy batchingStrategy) { - this(builder().driver(driver) - .embeddingModel(embeddingModel) - .sessionConfig(config.sessionConfig) + this(builder(driver, embeddingModel).sessionConfig(config.sessionConfig) .embeddingDimension(config.embeddingDimension) .distanceType(config.distanceType) .embeddingProperty(config.embeddingProperty) @@ -400,13 +398,13 @@ public class Neo4jVectorStore extends AbstractObservationVectorStore implements } - public static Neo4jBuilder builder() { - return new Neo4jBuilder(); + public static Neo4jBuilder builder(Driver driver, EmbeddingModel embeddingModel) { + return new Neo4jBuilder(driver, embeddingModel); } public static class Neo4jBuilder extends AbstractVectorStoreBuilder { - private Driver driver; + private final Driver driver; private SessionConfig sessionConfig = SessionConfig.defaultConfig(); @@ -428,10 +426,10 @@ public class Neo4jVectorStore extends AbstractObservationVectorStore implements private BatchingStrategy batchingStrategy = new TokenCountBatchingStrategy(); - public Neo4jBuilder driver(Driver driver) { + public Neo4jBuilder(Driver driver, EmbeddingModel embeddingModel) { + super(embeddingModel); Assert.notNull(driver, "Neo4j driver must not be null"); this.driver = driver; - return this; } /** @@ -565,7 +563,6 @@ public class Neo4jVectorStore extends AbstractObservationVectorStore implements @Override public Neo4jVectorStore build() { - validate(); return new Neo4jVectorStore(this); } diff --git a/vector-stores/spring-ai-neo4j-store/src/test/java/org/springframework/ai/vectorstore/neo4j/Neo4jVectorStoreIT.java b/vector-stores/spring-ai-neo4j-store/src/test/java/org/springframework/ai/vectorstore/neo4j/Neo4jVectorStoreIT.java index 401b8a559..b0d145c2d 100644 --- a/vector-stores/spring-ai-neo4j-store/src/test/java/org/springframework/ai/vectorstore/neo4j/Neo4jVectorStoreIT.java +++ b/vector-stores/spring-ai-neo4j-store/src/test/java/org/springframework/ai/vectorstore/neo4j/Neo4jVectorStoreIT.java @@ -291,11 +291,7 @@ class Neo4jVectorStoreIT { @Bean public VectorStore vectorStore(Driver driver, EmbeddingModel embeddingModel) { - return Neo4jVectorStore.builder() - .driver(driver) - .embeddingModel(embeddingModel) - .initializeSchema(true) - .build(); + return Neo4jVectorStore.builder(driver, embeddingModel).initializeSchema(true).build(); } @Bean diff --git a/vector-stores/spring-ai-neo4j-store/src/test/java/org/springframework/ai/vectorstore/neo4j/Neo4jVectorStoreObservationIT.java b/vector-stores/spring-ai-neo4j-store/src/test/java/org/springframework/ai/vectorstore/neo4j/Neo4jVectorStoreObservationIT.java index 0239f5454..4e48a0ba7 100644 --- a/vector-stores/spring-ai-neo4j-store/src/test/java/org/springframework/ai/vectorstore/neo4j/Neo4jVectorStoreObservationIT.java +++ b/vector-stores/spring-ai-neo4j-store/src/test/java/org/springframework/ai/vectorstore/neo4j/Neo4jVectorStoreObservationIT.java @@ -178,9 +178,7 @@ public class Neo4jVectorStoreObservationIT { public VectorStore vectorStore(Driver driver, EmbeddingModel embeddingModel, ObservationRegistry observationRegistry) { - return Neo4jVectorStore.builder() - .driver(driver) - .embeddingModel(embeddingModel) + return Neo4jVectorStore.builder(driver, embeddingModel) .initializeSchema(true) .observationRegistry(observationRegistry) .customObservationConvention(null) diff --git a/vector-stores/spring-ai-opensearch-store/src/main/java/org/springframework/ai/vectorstore/opensearch/OpenSearchVectorStore.java b/vector-stores/spring-ai-opensearch-store/src/main/java/org/springframework/ai/vectorstore/opensearch/OpenSearchVectorStore.java index 7a9bd4b41..13de4f672 100644 --- a/vector-stores/spring-ai-opensearch-store/src/main/java/org/springframework/ai/vectorstore/opensearch/OpenSearchVectorStore.java +++ b/vector-stores/spring-ai-opensearch-store/src/main/java/org/springframework/ai/vectorstore/opensearch/OpenSearchVectorStore.java @@ -238,9 +238,7 @@ public class OpenSearchVectorStore extends AbstractObservationVectorStore implem String mappingJson, boolean initializeSchema, ObservationRegistry observationRegistry, VectorStoreObservationConvention customObservationConvention, BatchingStrategy batchingStrategy) { - this(builder().openSearchClient(openSearchClient) - .embeddingModel(embeddingModel) - .index(index) + this(builder(openSearchClient, embeddingModel).index(index) .mappingJson(mappingJson) .initializeSchema(initializeSchema) .observationRegistry(observationRegistry) @@ -272,8 +270,8 @@ public class OpenSearchVectorStore extends AbstractObservationVectorStore implem * Creates a new builder instance for configuring an OpenSearchVectorStore. * @return A new OpenSearchBuilder instance */ - public static OpenSearchBuilder builder() { - return new OpenSearchBuilder(); + public static OpenSearchBuilder builder(OpenSearchClient openSearchClient, EmbeddingModel embeddingModel) { + return new OpenSearchBuilder(openSearchClient, embeddingModel); } public OpenSearchVectorStore withSimilarityFunction(String similarityFunction) { @@ -450,7 +448,7 @@ public class OpenSearchVectorStore extends AbstractObservationVectorStore implem */ public static class OpenSearchBuilder extends AbstractVectorStoreBuilder { - private OpenSearchClient openSearchClient; + private final OpenSearchClient openSearchClient; private String index = DEFAULT_INDEX_NAME; @@ -470,22 +468,10 @@ public class OpenSearchVectorStore extends AbstractObservationVectorStore implem * @return The builder instance * @throws IllegalArgumentException if openSearchClient is null */ - public OpenSearchBuilder openSearchClient(OpenSearchClient openSearchClient) { + public OpenSearchBuilder(OpenSearchClient openSearchClient, EmbeddingModel embeddingModel) { + super(embeddingModel); Assert.notNull(openSearchClient, "OpenSearchClient must not be null"); this.openSearchClient = openSearchClient; - return this; - } - - /** - * Sets the embedding model. - * @param embeddingModel The embedding model to use - * @return The builder instance - * @throws IllegalArgumentException if embeddingModel is null - */ - public OpenSearchBuilder embeddingModel(EmbeddingModel embeddingModel) { - Assert.notNull(embeddingModel, "EmbeddingModel must not be null"); - this.embeddingModel = embeddingModel; - return this; } /** @@ -567,7 +553,6 @@ public class OpenSearchVectorStore extends AbstractObservationVectorStore implem */ @Override public OpenSearchVectorStore build() { - validate(); return new OpenSearchVectorStore(this); } diff --git a/vector-stores/spring-ai-opensearch-store/src/test/java/org/springframework/ai/vectorstore/opensearch/OpenSearchVectorStoreIT.java b/vector-stores/spring-ai-opensearch-store/src/test/java/org/springframework/ai/vectorstore/opensearch/OpenSearchVectorStoreIT.java index e650efee8..ece9987b3 100644 --- a/vector-stores/spring-ai-opensearch-store/src/test/java/org/springframework/ai/vectorstore/opensearch/OpenSearchVectorStoreIT.java +++ b/vector-stores/spring-ai-opensearch-store/src/test/java/org/springframework/ai/vectorstore/opensearch/OpenSearchVectorStoreIT.java @@ -398,13 +398,10 @@ class OpenSearchVectorStoreIT { @Qualifier("vectorStore") public OpenSearchVectorStore vectorStore(EmbeddingModel embeddingModel) { try { - return OpenSearchVectorStore.builder() - .openSearchClient(new OpenSearchClient(ApacheHttpClient5TransportBuilder - .builder(HttpHost.create(opensearchContainer.getHttpHostAddress())) - .build())) - .embeddingModel(embeddingModel) - .initializeSchema(true) - .build(); + OpenSearchClient openSearchClient = new OpenSearchClient(ApacheHttpClient5TransportBuilder + .builder(HttpHost.create(opensearchContainer.getHttpHostAddress())) + .build()); + return OpenSearchVectorStore.builder(openSearchClient, embeddingModel).initializeSchema(true).build(); } catch (URISyntaxException e) { throw new RuntimeException(e); @@ -415,12 +412,11 @@ class OpenSearchVectorStoreIT { @Qualifier("anotherVectorStore") public OpenSearchVectorStore anotherVectorStore(EmbeddingModel embeddingModel) { try { - return OpenSearchVectorStore.builder() + OpenSearchClient openSearchClient = new OpenSearchClient(ApacheHttpClient5TransportBuilder + .builder(HttpHost.create(opensearchContainer.getHttpHostAddress())) + .build()); + return OpenSearchVectorStore.builder(openSearchClient, embeddingModel) .index("another_index") - .openSearchClient(new OpenSearchClient(ApacheHttpClient5TransportBuilder - .builder(HttpHost.create(opensearchContainer.getHttpHostAddress())) - .build())) - .embeddingModel(embeddingModel) .mappingJson(OpenSearchVectorStore.DEFAULT_MAPPING_EMBEDDING_TYPE_KNN_VECTOR_DIMENSION) .initializeSchema(true) .build(); diff --git a/vector-stores/spring-ai-opensearch-store/src/test/java/org/springframework/ai/vectorstore/opensearch/OpenSearchVectorStoreObservationIT.java b/vector-stores/spring-ai-opensearch-store/src/test/java/org/springframework/ai/vectorstore/opensearch/OpenSearchVectorStoreObservationIT.java index cba4321fb..8ae941939 100644 --- a/vector-stores/spring-ai-opensearch-store/src/test/java/org/springframework/ai/vectorstore/opensearch/OpenSearchVectorStoreObservationIT.java +++ b/vector-stores/spring-ai-opensearch-store/src/test/java/org/springframework/ai/vectorstore/opensearch/OpenSearchVectorStoreObservationIT.java @@ -207,12 +207,11 @@ public class OpenSearchVectorStoreObservationIT { public OpenSearchVectorStore vectorStore(EmbeddingModel embeddingModel, ObservationRegistry observationRegistry) { try { - return OpenSearchVectorStore.builder() + OpenSearchClient openSearchClient = new OpenSearchClient(ApacheHttpClient5TransportBuilder + .builder(HttpHost.create(opensearchContainer.getHttpHostAddress())) + .build()); + return OpenSearchVectorStore.builder(openSearchClient, embeddingModel) .index(OpenSearchVectorStore.DEFAULT_INDEX_NAME) - .openSearchClient(new OpenSearchClient(ApacheHttpClient5TransportBuilder - .builder(HttpHost.create(opensearchContainer.getHttpHostAddress())) - .build())) - .embeddingModel(embeddingModel) .mappingJson(OpenSearchVectorStore.DEFAULT_MAPPING_EMBEDDING_TYPE_KNN_VECTOR_DIMENSION) .initializeSchema(true) .observationRegistry(observationRegistry) diff --git a/vector-stores/spring-ai-opensearch-store/src/test/java/org/springframework/ai/vectorstore/opensearch/OpenSearchVectorStoreWithOllamaIT.java b/vector-stores/spring-ai-opensearch-store/src/test/java/org/springframework/ai/vectorstore/opensearch/OpenSearchVectorStoreWithOllamaIT.java index e6f802951..f34ae5293 100644 --- a/vector-stores/spring-ai-opensearch-store/src/test/java/org/springframework/ai/vectorstore/opensearch/OpenSearchVectorStoreWithOllamaIT.java +++ b/vector-stores/spring-ai-opensearch-store/src/test/java/org/springframework/ai/vectorstore/opensearch/OpenSearchVectorStoreWithOllamaIT.java @@ -169,13 +169,10 @@ class OpenSearchVectorStoreWithOllamaIT { @Qualifier("vectorStore") public OpenSearchVectorStore vectorStore(EmbeddingModel embeddingModel) { try { - return OpenSearchVectorStore.builder() - .openSearchClient(new OpenSearchClient(ApacheHttpClient5TransportBuilder - .builder(HttpHost.create(opensearchContainer.getHttpHostAddress())) - .build())) - .embeddingModel(embeddingModel) - .initializeSchema(true) - .build(); + OpenSearchClient openSearchClient = new OpenSearchClient(ApacheHttpClient5TransportBuilder + .builder(HttpHost.create(opensearchContainer.getHttpHostAddress())) + .build()); + return OpenSearchVectorStore.builder(openSearchClient, embeddingModel).initializeSchema(true).build(); } catch (URISyntaxException e) { throw new RuntimeException(e); @@ -186,12 +183,11 @@ class OpenSearchVectorStoreWithOllamaIT { @Qualifier("anotherVectorStore") public OpenSearchVectorStore anotherVectorStore(EmbeddingModel embeddingModel) { try { - return OpenSearchVectorStore.builder() + OpenSearchClient openSearchClient = new OpenSearchClient(ApacheHttpClient5TransportBuilder + .builder(HttpHost.create(opensearchContainer.getHttpHostAddress())) + .build()); + return OpenSearchVectorStore.builder(openSearchClient, embeddingModel) .index("another_index") - .openSearchClient(new OpenSearchClient(ApacheHttpClient5TransportBuilder - .builder(HttpHost.create(opensearchContainer.getHttpHostAddress())) - .build())) - .embeddingModel(embeddingModel) .mappingJson(OpenSearchVectorStore.DEFAULT_MAPPING_EMBEDDING_TYPE_KNN_VECTOR_DIMENSION) .initializeSchema(true) .build(); diff --git a/vector-stores/spring-ai-oracle-store/src/main/java/org/springframework/ai/vectorstore/oracle/OracleVectorStore.java b/vector-stores/spring-ai-oracle-store/src/main/java/org/springframework/ai/vectorstore/oracle/OracleVectorStore.java index c2a5a0e38..2f91346c7 100644 --- a/vector-stores/spring-ai-oracle-store/src/main/java/org/springframework/ai/vectorstore/oracle/OracleVectorStore.java +++ b/vector-stores/spring-ai-oracle-store/src/main/java/org/springframework/ai/vectorstore/oracle/OracleVectorStore.java @@ -220,9 +220,7 @@ public class OracleVectorStore extends AbstractObservationVectorStore implements boolean forcedNormalization, ObservationRegistry observationRegistry, VectorStoreObservationConvention customObservationConvention, BatchingStrategy batchingStrategy) { - this(builder().jdbcTemplate(jdbcTemplate) - .embeddingModel(embeddingModel) - .tableName(tableName) + this(builder(jdbcTemplate, embeddingModel).tableName(tableName) .indexType(indexType) .distanceType(distanceType) .dimensions(dimensions) @@ -257,8 +255,8 @@ public class OracleVectorStore extends AbstractObservationVectorStore implements this.batchingStrategy = builder.batchingStrategy; } - public static OracleBuilder builder() { - return new OracleBuilder(); + public static OracleBuilder builder(JdbcTemplate jdbcTemplate, EmbeddingModel embeddingModel) { + return new OracleBuilder(jdbcTemplate, embeddingModel); } @Override @@ -773,10 +771,10 @@ public class OracleVectorStore extends AbstractObservationVectorStore implements * @return the builder instance * @throws IllegalArgumentException if jdbcTemplate is null */ - public OracleBuilder jdbcTemplate(JdbcTemplate jdbcTemplate) { + public OracleBuilder(JdbcTemplate jdbcTemplate, EmbeddingModel embeddingModel) { + super(embeddingModel); Assert.notNull(jdbcTemplate, "JdbcTemplate must not be null"); this.jdbcTemplate = jdbcTemplate; - return this; } /** @@ -890,7 +888,6 @@ public class OracleVectorStore extends AbstractObservationVectorStore implements @Override public OracleVectorStore build() { - validate(); return new OracleVectorStore(this); } diff --git a/vector-stores/spring-ai-oracle-store/src/test/java/org/springframework/ai/vectorstore/oracle/OracleVectorStoreIT.java b/vector-stores/spring-ai-oracle-store/src/test/java/org/springframework/ai/vectorstore/oracle/OracleVectorStoreIT.java index 3130ff16b..48bedd937 100644 --- a/vector-stores/spring-ai-oracle-store/src/test/java/org/springframework/ai/vectorstore/oracle/OracleVectorStoreIT.java +++ b/vector-stores/spring-ai-oracle-store/src/test/java/org/springframework/ai/vectorstore/oracle/OracleVectorStoreIT.java @@ -310,9 +310,7 @@ public class OracleVectorStoreIT { @Bean public VectorStore vectorStore(JdbcTemplate jdbcTemplate, EmbeddingModel embeddingModel) { - return OracleVectorStore.builder() - .jdbcTemplate(jdbcTemplate) - .embeddingModel(embeddingModel) + return OracleVectorStore.builder(jdbcTemplate, embeddingModel) .tableName(OracleVectorStore.DEFAULT_TABLE_NAME) .indexType(OracleVectorStore.OracleVectorStoreIndexType.IVF) .distanceType(distanceType) diff --git a/vector-stores/spring-ai-oracle-store/src/test/java/org/springframework/ai/vectorstore/oracle/OracleVectorStoreObservationIT.java b/vector-stores/spring-ai-oracle-store/src/test/java/org/springframework/ai/vectorstore/oracle/OracleVectorStoreObservationIT.java index cd566647a..ab5a92af7 100644 --- a/vector-stores/spring-ai-oracle-store/src/test/java/org/springframework/ai/vectorstore/oracle/OracleVectorStoreObservationIT.java +++ b/vector-stores/spring-ai-oracle-store/src/test/java/org/springframework/ai/vectorstore/oracle/OracleVectorStoreObservationIT.java @@ -187,9 +187,7 @@ public class OracleVectorStoreObservationIT { @Bean public VectorStore vectorStore(JdbcTemplate jdbcTemplate, EmbeddingModel embeddingModel, ObservationRegistry observationRegistry) { - return OracleVectorStore.builder() - .jdbcTemplate(jdbcTemplate) - .embeddingModel(embeddingModel) + return OracleVectorStore.builder(jdbcTemplate, embeddingModel) .tableName(OracleVectorStore.DEFAULT_TABLE_NAME) .indexType(OracleVectorStore.OracleVectorStoreIndexType.IVF) .distanceType(OracleVectorStoreDistanceType.COSINE) diff --git a/vector-stores/spring-ai-pgvector-store/src/main/java/org/springframework/ai/vectorstore/pgvector/PgVectorStore.java b/vector-stores/spring-ai-pgvector-store/src/main/java/org/springframework/ai/vectorstore/pgvector/PgVectorStore.java index cdd055316..8c29d1a63 100644 --- a/vector-stores/spring-ai-pgvector-store/src/main/java/org/springframework/ai/vectorstore/pgvector/PgVectorStore.java +++ b/vector-stores/spring-ai-pgvector-store/src/main/java/org/springframework/ai/vectorstore/pgvector/PgVectorStore.java @@ -239,8 +239,7 @@ public class PgVectorStore extends AbstractObservationVectorStore implements Ini int dimensions, PgDistanceType distanceType, boolean removeExistingVectorStoreTable, PgIndexType createIndexMethod, boolean initializeSchema) { - this(builder().jdbcTemplate(jdbcTemplate) - .schemaName(DEFAULT_SCHEMA_NAME) + this(builder(jdbcTemplate, embeddingModel).schemaName(DEFAULT_SCHEMA_NAME) .vectorTableName(vectorTableName) .vectorTableValidationsEnabled(DEFAULT_SCHEMA_VALIDATION) .dimensions(dimensions) @@ -286,8 +285,8 @@ public class PgVectorStore extends AbstractObservationVectorStore implements Ini return this.distanceType; } - public static PgVectorStoreBuilder builder() { - return new PgVectorStoreBuilder(); + public static PgVectorStoreBuilder builder(JdbcTemplate jdbcTemplate, EmbeddingModel embeddingModel) { + return new PgVectorStoreBuilder(jdbcTemplate, embeddingModel); } @Override @@ -647,10 +646,10 @@ public class PgVectorStore extends AbstractObservationVectorStore implements Ini private int maxDocumentBatchSize = MAX_DOCUMENT_BATCH_SIZE; - public PgVectorStoreBuilder jdbcTemplate(JdbcTemplate jdbcTemplate) { + private PgVectorStoreBuilder(JdbcTemplate jdbcTemplate, EmbeddingModel embeddingModel) { + super(embeddingModel); Assert.notNull(jdbcTemplate, "JdbcTemplate must not be null"); this.jdbcTemplate = jdbcTemplate; - return this; } public PgVectorStoreBuilder schemaName(String schemaName) { @@ -704,7 +703,6 @@ public class PgVectorStore extends AbstractObservationVectorStore implements Ini } public PgVectorStore build() { - validate(); return new PgVectorStore(this); } @@ -811,9 +809,7 @@ public class PgVectorStore extends AbstractObservationVectorStore implements Ini } public PgVectorStore build() { - return PgVectorStore.builder() - .jdbcTemplate(this.jdbcTemplate) - .embeddingModel(this.embeddingModel) + return PgVectorStore.builder(this.jdbcTemplate, this.embeddingModel) .schemaName(this.schemaName) .vectorTableName(this.vectorTableName) .vectorTableValidationsEnabled(this.vectorTableValidationsEnabled) diff --git a/vector-stores/spring-ai-pgvector-store/src/test/java/org/springframework/ai/vectorstore/pgvector/PgVectorEmbeddingDimensionsTests.java b/vector-stores/spring-ai-pgvector-store/src/test/java/org/springframework/ai/vectorstore/pgvector/PgVectorEmbeddingDimensionsTests.java index f2ace8540..e3bee959e 100644 --- a/vector-stores/spring-ai-pgvector-store/src/test/java/org/springframework/ai/vectorstore/pgvector/PgVectorEmbeddingDimensionsTests.java +++ b/vector-stores/spring-ai-pgvector-store/src/test/java/org/springframework/ai/vectorstore/pgvector/PgVectorEmbeddingDimensionsTests.java @@ -47,9 +47,7 @@ public class PgVectorEmbeddingDimensionsTests { final int explicitDimensions = 696; - PgVectorStore pgVectorStore = PgVectorStore.builder() - .jdbcTemplate(this.jdbcTemplate) - .embeddingModel(this.embeddingModel) + PgVectorStore pgVectorStore = PgVectorStore.builder(this.jdbcTemplate, this.embeddingModel) .dimensions(explicitDimensions) .build(); var dim = pgVectorStore.embeddingDimensions(); @@ -62,10 +60,7 @@ public class PgVectorEmbeddingDimensionsTests { public void embeddingModelDimensions() { given(this.embeddingModel.dimensions()).willReturn(969); - PgVectorStore pgVectorStore = PgVectorStore.builder() - .jdbcTemplate(this.jdbcTemplate) - .embeddingModel(this.embeddingModel) - .build(); + PgVectorStore pgVectorStore = PgVectorStore.builder(this.jdbcTemplate, this.embeddingModel).build(); var dim = pgVectorStore.embeddingDimensions(); assertThat(dim).isEqualTo(969); @@ -78,10 +73,7 @@ public class PgVectorEmbeddingDimensionsTests { given(this.embeddingModel.dimensions()).willThrow(new RuntimeException()); - PgVectorStore pgVectorStore = PgVectorStore.builder() - .jdbcTemplate(this.jdbcTemplate) - .embeddingModel(this.embeddingModel) - .build(); + PgVectorStore pgVectorStore = PgVectorStore.builder(this.jdbcTemplate, this.embeddingModel).build(); var dim = pgVectorStore.embeddingDimensions(); assertThat(dim).isEqualTo(PgVectorStore.OPENAI_EMBEDDING_DIMENSION_SIZE); diff --git a/vector-stores/spring-ai-pgvector-store/src/test/java/org/springframework/ai/vectorstore/pgvector/PgVectorStoreCustomNamesIT.java b/vector-stores/spring-ai-pgvector-store/src/test/java/org/springframework/ai/vectorstore/pgvector/PgVectorStoreCustomNamesIT.java index e6f6fbc77..8c3ddd751 100644 --- a/vector-stores/spring-ai-pgvector-store/src/test/java/org/springframework/ai/vectorstore/pgvector/PgVectorStoreCustomNamesIT.java +++ b/vector-stores/spring-ai-pgvector-store/src/test/java/org/springframework/ai/vectorstore/pgvector/PgVectorStoreCustomNamesIT.java @@ -196,9 +196,7 @@ public class PgVectorStoreCustomNamesIT { @Bean public VectorStore vectorStore(JdbcTemplate jdbcTemplate, EmbeddingModel embeddingModel) { - return PgVectorStore.builder() - .jdbcTemplate(jdbcTemplate) - .embeddingModel(embeddingModel) + return PgVectorStore.builder(jdbcTemplate, embeddingModel) .schemaName(this.schemaName) .vectorTableName(this.vectorTableName) .vectorTableValidationsEnabled(this.schemaValidation) diff --git a/vector-stores/spring-ai-pgvector-store/src/test/java/org/springframework/ai/vectorstore/pgvector/PgVectorStoreIT.java b/vector-stores/spring-ai-pgvector-store/src/test/java/org/springframework/ai/vectorstore/pgvector/PgVectorStoreIT.java index 4dbf74e95..7e926fa1d 100644 --- a/vector-stores/spring-ai-pgvector-store/src/test/java/org/springframework/ai/vectorstore/pgvector/PgVectorStoreIT.java +++ b/vector-stores/spring-ai-pgvector-store/src/test/java/org/springframework/ai/vectorstore/pgvector/PgVectorStoreIT.java @@ -356,9 +356,7 @@ public class PgVectorStoreIT { @Bean public VectorStore vectorStore(JdbcTemplate jdbcTemplate, EmbeddingModel embeddingModel) { - return PgVectorStore.builder() - .jdbcTemplate(jdbcTemplate) - .embeddingModel(embeddingModel) + return PgVectorStore.builder(jdbcTemplate, embeddingModel) .dimensions(PgVectorStore.INVALID_EMBEDDING_DIMENSION) .distanceType(this.distanceType) .initializeSchema(true) diff --git a/vector-stores/spring-ai-pgvector-store/src/test/java/org/springframework/ai/vectorstore/pgvector/PgVectorStoreObservationIT.java b/vector-stores/spring-ai-pgvector-store/src/test/java/org/springframework/ai/vectorstore/pgvector/PgVectorStoreObservationIT.java index 88aba5b80..4dae0f1a6 100644 --- a/vector-stores/spring-ai-pgvector-store/src/test/java/org/springframework/ai/vectorstore/pgvector/PgVectorStoreObservationIT.java +++ b/vector-stores/spring-ai-pgvector-store/src/test/java/org/springframework/ai/vectorstore/pgvector/PgVectorStoreObservationIT.java @@ -187,9 +187,7 @@ public class PgVectorStoreObservationIT { @Bean public VectorStore vectorStore(JdbcTemplate jdbcTemplate, EmbeddingModel embeddingModel, ObservationRegistry observationRegistry) { - return PgVectorStore.builder() - .jdbcTemplate(jdbcTemplate) - .embeddingModel(embeddingModel) + return PgVectorStore.builder(jdbcTemplate, embeddingModel) .distanceType(PgVectorStore.PgDistanceType.COSINE_DISTANCE) .indexType(PgIndexType.HNSW) .observationRegistry(observationRegistry) diff --git a/vector-stores/spring-ai-pgvector-store/src/test/java/org/springframework/ai/vectorstore/pgvector/PgVectorStoreTests.java b/vector-stores/spring-ai-pgvector-store/src/test/java/org/springframework/ai/vectorstore/pgvector/PgVectorStoreTests.java index 656220e71..cfe63b81e 100644 --- a/vector-stores/spring-ai-pgvector-store/src/test/java/org/springframework/ai/vectorstore/pgvector/PgVectorStoreTests.java +++ b/vector-stores/spring-ai-pgvector-store/src/test/java/org/springframework/ai/vectorstore/pgvector/PgVectorStoreTests.java @@ -79,11 +79,7 @@ public class PgVectorStoreTests { // Given var jdbcTemplate = mock(JdbcTemplate.class); var embeddingModel = mock(EmbeddingModel.class); - var pgVectorStore = PgVectorStore.builder() - .jdbcTemplate(jdbcTemplate) - .embeddingModel(embeddingModel) - .maxDocumentBatchSize(1000) - .build(); + var pgVectorStore = PgVectorStore.builder(jdbcTemplate, embeddingModel).maxDocumentBatchSize(1000).build(); // Testing with 9989 documents var documents = Collections.nCopies(9989, new Document("foo")); diff --git a/vector-stores/spring-ai-pinecone-store/src/main/java/org/springframework/ai/vectorstore/pinecone/PineconeVectorStore.java b/vector-stores/spring-ai-pinecone-store/src/main/java/org/springframework/ai/vectorstore/pinecone/PineconeVectorStore.java index df471a796..b34c6ced3 100644 --- a/vector-stores/spring-ai-pinecone-store/src/main/java/org/springframework/ai/vectorstore/pinecone/PineconeVectorStore.java +++ b/vector-stores/spring-ai-pinecone-store/src/main/java/org/springframework/ai/vectorstore/pinecone/PineconeVectorStore.java @@ -109,8 +109,7 @@ public class PineconeVectorStore extends AbstractObservationVectorStore { public PineconeVectorStore(PineconeVectorStoreConfig config, EmbeddingModel embeddingModel, ObservationRegistry observationRegistry, VectorStoreObservationConvention customObservationConvention, BatchingStrategy batchingStrategy) { - this(builder().embeddingModel(embeddingModel) - .apiKey(config.clientConfig.getApiKey()) + this(builder(embeddingModel).apiKey(config.clientConfig.getApiKey()) .projectId(config.clientConfig.getProjectName()) .environment(config.clientConfig.getEnvironment()) .indexName(config.connectionConfig.getIndexName()) @@ -156,8 +155,8 @@ public class PineconeVectorStore extends AbstractObservationVectorStore { * Creates a new builder instance for configuring a PineconeVectorStore. * @return A new PineconeBuilder instance */ - public static PineconeBuilder builder() { - return new PineconeBuilder(); + public static PineconeBuilder builder(EmbeddingModel embeddingModel) { + return new PineconeBuilder(embeddingModel); } /** @@ -358,6 +357,10 @@ public class PineconeVectorStore extends AbstractObservationVectorStore { private BatchingStrategy batchingStrategy = new TokenCountBatchingStrategy(); + private PineconeBuilder(EmbeddingModel embeddingModel) { + super(embeddingModel); + } + /** * Sets the Pinecone API key. * @param apiKey The API key to use @@ -467,7 +470,6 @@ public class PineconeVectorStore extends AbstractObservationVectorStore { */ @Override public PineconeVectorStore build() { - validate(); return new PineconeVectorStore(this); } diff --git a/vector-stores/spring-ai-pinecone-store/src/test/java/org/springframework/ai/vectorstore/pinecone/PineconeVectorStoreIT.java b/vector-stores/spring-ai-pinecone-store/src/test/java/org/springframework/ai/vectorstore/pinecone/PineconeVectorStoreIT.java index 4e05e1e12..c128acaef 100644 --- a/vector-stores/spring-ai-pinecone-store/src/test/java/org/springframework/ai/vectorstore/pinecone/PineconeVectorStoreIT.java +++ b/vector-stores/spring-ai-pinecone-store/src/test/java/org/springframework/ai/vectorstore/pinecone/PineconeVectorStoreIT.java @@ -275,8 +275,7 @@ public class PineconeVectorStoreIT { @Bean public VectorStore vectorStore(EmbeddingModel embeddingModel) { String apikey = System.getenv("PINECONE_API_KEY"); - return PineconeVectorStore.builder() - .embeddingModel(embeddingModel) + return PineconeVectorStore.builder(embeddingModel) .apiKey(apikey) .environment(PINECONE_ENVIRONMENT) .projectId(PINECONE_PROJECT_ID) diff --git a/vector-stores/spring-ai-pinecone-store/src/test/java/org/springframework/ai/vectorstore/pinecone/PineconeVectorStoreObservationIT.java b/vector-stores/spring-ai-pinecone-store/src/test/java/org/springframework/ai/vectorstore/pinecone/PineconeVectorStoreObservationIT.java index 02c611576..5cf5573b3 100644 --- a/vector-stores/spring-ai-pinecone-store/src/test/java/org/springframework/ai/vectorstore/pinecone/PineconeVectorStoreObservationIT.java +++ b/vector-stores/spring-ai-pinecone-store/src/test/java/org/springframework/ai/vectorstore/pinecone/PineconeVectorStoreObservationIT.java @@ -187,8 +187,7 @@ public class PineconeVectorStoreObservationIT { @Bean public VectorStore vectorStore(EmbeddingModel embeddingModel, ObservationRegistry observationRegistry) { - return PineconeVectorStore.builder() - .embeddingModel(embeddingModel) + return PineconeVectorStore.builder(embeddingModel) .apiKey(System.getenv("PINECONE_API_KEY")) .environment(PINECONE_ENVIRONMENT) .projectId(PINECONE_PROJECT_ID) diff --git a/vector-stores/spring-ai-qdrant-store/src/main/java/org/springframework/ai/vectorstore/qdrant/QdrantVectorStore.java b/vector-stores/spring-ai-qdrant-store/src/main/java/org/springframework/ai/vectorstore/qdrant/QdrantVectorStore.java index 0630fa160..be315413b 100644 --- a/vector-stores/spring-ai-qdrant-store/src/main/java/org/springframework/ai/vectorstore/qdrant/QdrantVectorStore.java +++ b/vector-stores/spring-ai-qdrant-store/src/main/java/org/springframework/ai/vectorstore/qdrant/QdrantVectorStore.java @@ -149,7 +149,7 @@ public class QdrantVectorStore extends AbstractObservationVectorStore implements * @param collectionName The name of the collection to use in Qdrant. * @param embeddingModel The client for embedding operations. * @param initializeSchema A boolean indicating whether to initialize the schema. - * @deprecated Use {@link #builder(QdrantClient)} + * @deprecated Use {@link #builder(QdrantClient, EmbeddingModel)} */ @Deprecated(forRemoval = true, since = "1.0.0-M5") public QdrantVectorStore(QdrantClient qdrantClient, String collectionName, EmbeddingModel embeddingModel, @@ -166,15 +166,14 @@ public class QdrantVectorStore extends AbstractObservationVectorStore implements * @param initializeSchema A boolean indicating whether to initialize the schema. * @param observationRegistry The observation registry to use. * @param customObservationConvention The custom search observation convention to use. - * @deprecated Use {@link #builder(QdrantClient)} + * @deprecated Use {@link #builder(QdrantClient, EmbeddingModel)} */ @Deprecated(forRemoval = true, since = "1.0.0-M5") public QdrantVectorStore(QdrantClient qdrantClient, String collectionName, EmbeddingModel embeddingModel, boolean initializeSchema, ObservationRegistry observationRegistry, VectorStoreObservationConvention customObservationConvention, BatchingStrategy batchingStrategy) { - this(builder(qdrantClient).embeddingModel(embeddingModel) - .collectionName(collectionName) + this(builder(qdrantClient, embeddingModel).collectionName(collectionName) .initializeSchema(initializeSchema) .observationRegistry(observationRegistry) .customObservationConvention(customObservationConvention) @@ -206,8 +205,8 @@ public class QdrantVectorStore extends AbstractObservationVectorStore implements * @param qdrantClient the client for interfacing with Qdrant * @return a new QdrantBuilder instance */ - public static QdrantBuilder builder(QdrantClient qdrantClient) { - return new QdrantBuilder(qdrantClient); + public static QdrantBuilder builder(QdrantClient qdrantClient, EmbeddingModel embeddingModel) { + return new QdrantBuilder(qdrantClient, embeddingModel); } /** @@ -386,7 +385,8 @@ public class QdrantVectorStore extends AbstractObservationVectorStore implements * @param qdrantClient the client for Qdrant operations * @throws IllegalArgumentException if qdrantClient is null */ - QdrantBuilder(QdrantClient qdrantClient) { + private QdrantBuilder(QdrantClient qdrantClient, EmbeddingModel embeddingModel) { + super(embeddingModel); Assert.notNull(qdrantClient, "QdrantClient must not be null"); this.qdrantClient = qdrantClient; } @@ -434,7 +434,6 @@ public class QdrantVectorStore extends AbstractObservationVectorStore implements */ @Override public QdrantVectorStore build() { - validate(); return new QdrantVectorStore(this); } diff --git a/vector-stores/spring-ai-qdrant-store/src/test/java/org/springframework/ai/vectorstore/qdrant/QdrantVectorStoreBuilderTests.java b/vector-stores/spring-ai-qdrant-store/src/test/java/org/springframework/ai/vectorstore/qdrant/QdrantVectorStoreBuilderTests.java index e681a40bb..bbdfa73fa 100644 --- a/vector-stores/spring-ai-qdrant-store/src/test/java/org/springframework/ai/vectorstore/qdrant/QdrantVectorStoreBuilderTests.java +++ b/vector-stores/spring-ai-qdrant-store/src/test/java/org/springframework/ai/vectorstore/qdrant/QdrantVectorStoreBuilderTests.java @@ -46,7 +46,7 @@ class QdrantVectorStoreBuilderTests { @Test void defaultConfiguration() { - QdrantVectorStore vectorStore = QdrantVectorStore.builder(qdrantClient).embeddingModel(embeddingModel).build(); + QdrantVectorStore vectorStore = QdrantVectorStore.builder(qdrantClient, embeddingModel).build(); // Verify default values assertThat(vectorStore).hasFieldOrPropertyWithValue("collectionName", "vector_store"); @@ -56,8 +56,7 @@ class QdrantVectorStoreBuilderTests { @Test void customConfiguration() { - QdrantVectorStore vectorStore = QdrantVectorStore.builder(qdrantClient) - .embeddingModel(embeddingModel) + QdrantVectorStore vectorStore = QdrantVectorStore.builder(qdrantClient, embeddingModel) .collectionName("custom_collection") .initializeSchema(true) .batchingStrategy(new TokenCountBatchingStrategy()) @@ -70,31 +69,29 @@ class QdrantVectorStoreBuilderTests { @Test void nullQdrantClientInConstructorShouldThrowException() { - assertThatThrownBy(() -> QdrantVectorStore.builder(null)).isInstanceOf(IllegalArgumentException.class) + assertThatThrownBy(() -> QdrantVectorStore.builder(null, null)).isInstanceOf(IllegalArgumentException.class) .hasMessage("QdrantClient must not be null"); } @Test void nullEmbeddingModelShouldThrowException() { - assertThatThrownBy(() -> QdrantVectorStore.builder(qdrantClient).embeddingModel(null).build()) + assertThatThrownBy(() -> QdrantVectorStore.builder(qdrantClient, null).build()) .isInstanceOf(IllegalArgumentException.class) .hasMessage("EmbeddingModel must not be null"); } @Test void emptyCollectionNameShouldThrowException() { - assertThatThrownBy( - () -> QdrantVectorStore.builder(qdrantClient).embeddingModel(embeddingModel).collectionName("").build()) + assertThatThrownBy(() -> QdrantVectorStore.builder(qdrantClient, embeddingModel).collectionName("").build()) .isInstanceOf(IllegalArgumentException.class) .hasMessage("collectionName must not be empty"); } @Test void nullBatchingStrategyShouldThrowException() { - assertThatThrownBy(() -> QdrantVectorStore.builder(qdrantClient) - .embeddingModel(embeddingModel) - .batchingStrategy(null) - .build()).isInstanceOf(IllegalArgumentException.class).hasMessage("BatchingStrategy must not be null"); + assertThatThrownBy(() -> QdrantVectorStore.builder(qdrantClient, embeddingModel).batchingStrategy(null).build()) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("BatchingStrategy must not be null"); } } diff --git a/vector-stores/spring-ai-qdrant-store/src/test/java/org/springframework/ai/vectorstore/qdrant/QdrantVectorStoreIT.java b/vector-stores/spring-ai-qdrant-store/src/test/java/org/springframework/ai/vectorstore/qdrant/QdrantVectorStoreIT.java index 282fb5577..b5a89c893 100644 --- a/vector-stores/spring-ai-qdrant-store/src/test/java/org/springframework/ai/vectorstore/qdrant/QdrantVectorStoreIT.java +++ b/vector-stores/spring-ai-qdrant-store/src/test/java/org/springframework/ai/vectorstore/qdrant/QdrantVectorStoreIT.java @@ -254,9 +254,8 @@ public class QdrantVectorStoreIT { @Bean public VectorStore qdrantVectorStore(EmbeddingModel embeddingModel, QdrantClient qdrantClient) { - return QdrantVectorStore.builder(qdrantClient) + return QdrantVectorStore.builder(qdrantClient, embeddingModel) .collectionName(COLLECTION_NAME) - .embeddingModel(embeddingModel) .initializeSchema(true) .build(); } diff --git a/vector-stores/spring-ai-qdrant-store/src/test/java/org/springframework/ai/vectorstore/qdrant/QdrantVectorStoreObservationIT.java b/vector-stores/spring-ai-qdrant-store/src/test/java/org/springframework/ai/vectorstore/qdrant/QdrantVectorStoreObservationIT.java index f54a2b480..a227b7d54 100644 --- a/vector-stores/spring-ai-qdrant-store/src/test/java/org/springframework/ai/vectorstore/qdrant/QdrantVectorStoreObservationIT.java +++ b/vector-stores/spring-ai-qdrant-store/src/test/java/org/springframework/ai/vectorstore/qdrant/QdrantVectorStoreObservationIT.java @@ -195,9 +195,8 @@ public class QdrantVectorStoreObservationIT { @Bean public VectorStore qdrantVectorStore(EmbeddingModel embeddingModel, QdrantClient qdrantClient, ObservationRegistry observationRegistry) { - return QdrantVectorStore.builder(qdrantClient) + return QdrantVectorStore.builder(qdrantClient, embeddingModel) .collectionName(COLLECTION_NAME) - .embeddingModel(embeddingModel) .initializeSchema(true) .observationRegistry(observationRegistry) .customObservationConvention(null) diff --git a/vector-stores/spring-ai-redis-store/src/main/java/org/springframework/ai/vectorstore/redis/RedisVectorStore.java b/vector-stores/spring-ai-redis-store/src/main/java/org/springframework/ai/vectorstore/redis/RedisVectorStore.java index ad801d089..a6aeed0d8 100644 --- a/vector-stores/spring-ai-redis-store/src/main/java/org/springframework/ai/vectorstore/redis/RedisVectorStore.java +++ b/vector-stores/spring-ai-redis-store/src/main/java/org/springframework/ai/vectorstore/redis/RedisVectorStore.java @@ -248,9 +248,7 @@ public class RedisVectorStore extends AbstractObservationVectorStore implements boolean initializeSchema, ObservationRegistry observationRegistry, VectorStoreObservationConvention customObservationConvention, BatchingStrategy batchingStrategy) { - this(builder().jedis(jedis) - .embeddingModel(embeddingModel) - .indexName(config.indexName) + this(builder(jedis, embeddingModel).indexName(config.indexName) .prefix(config.prefix) .contentFieldName(config.contentFieldName) .embeddingFieldName(config.embeddingFieldName) @@ -483,13 +481,13 @@ public class RedisVectorStore extends AbstractObservationVectorStore implements } - public static RedisBuilder builder() { - return new RedisBuilder(); + public static RedisBuilder builder(JedisPooled jedis, EmbeddingModel embeddingModel) { + return new RedisBuilder(jedis, embeddingModel); } public static class RedisBuilder extends AbstractVectorStoreBuilder { - private JedisPooled jedis; + private final JedisPooled jedis; private String indexName = DEFAULT_INDEX_NAME; @@ -507,10 +505,10 @@ public class RedisVectorStore extends AbstractObservationVectorStore implements private BatchingStrategy batchingStrategy = new TokenCountBatchingStrategy(); - public RedisBuilder jedis(JedisPooled jedis) { + public RedisBuilder(JedisPooled jedis, EmbeddingModel embeddingModel) { + super(embeddingModel); Assert.notNull(jedis, "JedisPooled must not be null"); this.jedis = jedis; - return this; } /** @@ -618,7 +616,6 @@ public class RedisVectorStore extends AbstractObservationVectorStore implements @Override public RedisVectorStore build() { - validate(); return new RedisVectorStore(this); } diff --git a/vector-stores/spring-ai-redis-store/src/test/java/org/springframework/ai/vectorstore/redis/RedisVectorStoreIT.java b/vector-stores/spring-ai-redis-store/src/test/java/org/springframework/ai/vectorstore/redis/RedisVectorStoreIT.java index 250f07b25..8973e56f2 100644 --- a/vector-stores/spring-ai-redis-store/src/test/java/org/springframework/ai/vectorstore/redis/RedisVectorStoreIT.java +++ b/vector-stores/spring-ai-redis-store/src/test/java/org/springframework/ai/vectorstore/redis/RedisVectorStoreIT.java @@ -256,9 +256,9 @@ class RedisVectorStoreIT { @Bean public RedisVectorStore vectorStore(EmbeddingModel embeddingModel, JedisConnectionFactory jedisConnectionFactory) { - return RedisVectorStore.builder() - .jedis(new JedisPooled(jedisConnectionFactory.getHostName(), jedisConnectionFactory.getPort())) - .embeddingModel(embeddingModel) + return RedisVectorStore + .builder(new JedisPooled(jedisConnectionFactory.getHostName(), jedisConnectionFactory.getPort()), + embeddingModel) .metadataFields(MetadataField.tag("meta1"), MetadataField.tag("meta2"), MetadataField.tag("country"), MetadataField.numeric("year")) .initializeSchema(true) diff --git a/vector-stores/spring-ai-redis-store/src/test/java/org/springframework/ai/vectorstore/redis/RedisVectorStoreObservationIT.java b/vector-stores/spring-ai-redis-store/src/test/java/org/springframework/ai/vectorstore/redis/RedisVectorStoreObservationIT.java index b88928f04..8b8ed2130 100644 --- a/vector-stores/spring-ai-redis-store/src/test/java/org/springframework/ai/vectorstore/redis/RedisVectorStoreObservationIT.java +++ b/vector-stores/spring-ai-redis-store/src/test/java/org/springframework/ai/vectorstore/redis/RedisVectorStoreObservationIT.java @@ -176,9 +176,9 @@ public class RedisVectorStoreObservationIT { @Bean public RedisVectorStore vectorStore(EmbeddingModel embeddingModel, JedisConnectionFactory jedisConnectionFactory, ObservationRegistry observationRegistry) { - return RedisVectorStore.builder() - .jedis(new JedisPooled(jedisConnectionFactory.getHostName(), jedisConnectionFactory.getPort())) - .embeddingModel(embeddingModel) + return RedisVectorStore + .builder(new JedisPooled(jedisConnectionFactory.getHostName(), jedisConnectionFactory.getPort()), + embeddingModel) .observationRegistry(observationRegistry) .customObservationConvention(null) .initializeSchema(true) diff --git a/vector-stores/spring-ai-typesense-store/src/main/java/org/springframework/ai/vectorstore/typesense/TypesenseVectorStore.java b/vector-stores/spring-ai-typesense-store/src/main/java/org/springframework/ai/vectorstore/typesense/TypesenseVectorStore.java index d15103680..73f129c4e 100644 --- a/vector-stores/spring-ai-typesense-store/src/main/java/org/springframework/ai/vectorstore/typesense/TypesenseVectorStore.java +++ b/vector-stores/spring-ai-typesense-store/src/main/java/org/springframework/ai/vectorstore/typesense/TypesenseVectorStore.java @@ -194,9 +194,7 @@ public class TypesenseVectorStore extends AbstractObservationVectorStore impleme boolean initializeSchema, ObservationRegistry observationRegistry, VectorStoreObservationConvention customObservationConvention, BatchingStrategy batchingStrategy) { - this(builder().client(client) - .embeddingModel(embeddingModel) - .collectionName(config.collectionName) + this(builder(client, embeddingModel).collectionName(config.collectionName) .embeddingDimension(config.embeddingDimension) .initializeSchema(initializeSchema) .observationRegistry(observationRegistry) @@ -232,8 +230,8 @@ public class TypesenseVectorStore extends AbstractObservationVectorStore impleme * a TypesenseVectorStore. * @return a new TypesenseBuilder instance */ - public static TypesenseBuilder builder() { - return new TypesenseBuilder(); + public static TypesenseBuilder builder(Client client, EmbeddingModel embeddingModel) { + return new TypesenseBuilder(client, embeddingModel); } @Override @@ -455,7 +453,7 @@ public class TypesenseVectorStore extends AbstractObservationVectorStore impleme private int embeddingDimension = INVALID_EMBEDDING_DIMENSION; - private Client client; + private final Client client; private boolean initializeSchema = false; @@ -467,10 +465,10 @@ public class TypesenseVectorStore extends AbstractObservationVectorStore impleme * @return this builder instance * @throws IllegalArgumentException if client is null */ - public TypesenseBuilder client(Client client) { + public TypesenseBuilder(Client client, EmbeddingModel embeddingModel) { + super(embeddingModel); Assert.notNull(client, "client must not be null"); this.client = client; - return this; } /** @@ -521,7 +519,6 @@ public class TypesenseVectorStore extends AbstractObservationVectorStore impleme @Override public TypesenseVectorStore build() { - validate(); return new TypesenseVectorStore(this); } diff --git a/vector-stores/spring-ai-typesense-store/src/test/java/org/springframework/ai/vectorstore/typesense/TypesenseVectorStoreBuilderTests.java b/vector-stores/spring-ai-typesense-store/src/test/java/org/springframework/ai/vectorstore/typesense/TypesenseVectorStoreBuilderTests.java index abb51de80..4e1bde08a 100644 --- a/vector-stores/spring-ai-typesense-store/src/test/java/org/springframework/ai/vectorstore/typesense/TypesenseVectorStoreBuilderTests.java +++ b/vector-stores/spring-ai-typesense-store/src/test/java/org/springframework/ai/vectorstore/typesense/TypesenseVectorStoreBuilderTests.java @@ -51,10 +51,7 @@ class TypesenseVectorStoreBuilderTests { @Test void defaultConfiguration() { - TypesenseVectorStore vectorStore = TypesenseVectorStore.builder() - .client(client) - .embeddingModel(embeddingModel) - .build(); + TypesenseVectorStore vectorStore = TypesenseVectorStore.builder(client, embeddingModel).build(); // Verify default values assertThat(vectorStore).hasFieldOrPropertyWithValue("collectionName", "vector_store"); @@ -65,9 +62,7 @@ class TypesenseVectorStoreBuilderTests { @Test void customConfiguration() { - TypesenseVectorStore vectorStore = TypesenseVectorStore.builder() - .client(client) - .embeddingModel(embeddingModel) + TypesenseVectorStore vectorStore = TypesenseVectorStore.builder(client, embeddingModel) .collectionName("custom_collection") .embeddingDimension(1536) .initializeSchema(true) @@ -80,44 +75,37 @@ class TypesenseVectorStoreBuilderTests { @Test void nullClientShouldThrowException() { - assertThatThrownBy(() -> TypesenseVectorStore.builder().client(null).build()) + assertThatThrownBy(() -> TypesenseVectorStore.builder(null, embeddingModel).build()) .isInstanceOf(IllegalArgumentException.class) .hasMessage("client must not be null"); } @Test void nullEmbeddingModelShouldThrowException() { - assertThatThrownBy(() -> TypesenseVectorStore.builder().client(client).embeddingModel(null).build()) + assertThatThrownBy(() -> TypesenseVectorStore.builder(client, null).build()) .isInstanceOf(IllegalArgumentException.class) - .hasMessage("EmbeddingModel must not be null"); + .hasMessage("EmbeddingModel must be configured"); } @Test void invalidEmbeddingDimensionShouldThrowException() { - assertThatThrownBy(() -> TypesenseVectorStore.builder() - .client(client) - .embeddingModel(embeddingModel) - .embeddingDimension(0) - .build()).isInstanceOf(IllegalArgumentException.class) + assertThatThrownBy(() -> TypesenseVectorStore.builder(client, embeddingModel).embeddingDimension(0).build()) + .isInstanceOf(IllegalArgumentException.class) .hasMessage("Embedding dimension must be greater than 0"); } @Test void emptyCollectionNameShouldThrowException() { - assertThatThrownBy(() -> TypesenseVectorStore.builder() - .client(client) - .embeddingModel(embeddingModel) - .collectionName("") - .build()).isInstanceOf(IllegalArgumentException.class).hasMessage("collectionName must not be empty"); + assertThatThrownBy(() -> TypesenseVectorStore.builder(client, embeddingModel).collectionName("").build()) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("collectionName must not be empty"); } @Test void nullBatchingStrategyShouldThrowException() { - assertThatThrownBy(() -> TypesenseVectorStore.builder() - .client(client) - .embeddingModel(embeddingModel) - .batchingStrategy(null) - .build()).isInstanceOf(IllegalArgumentException.class).hasMessage("batchingStrategy must not be null"); + assertThatThrownBy(() -> TypesenseVectorStore.builder(client, embeddingModel).batchingStrategy(null).build()) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("batchingStrategy must not be null"); } } diff --git a/vector-stores/spring-ai-typesense-store/src/test/java/org/springframework/ai/vectorstore/typesense/TypesenseVectorStoreIT.java b/vector-stores/spring-ai-typesense-store/src/test/java/org/springframework/ai/vectorstore/typesense/TypesenseVectorStoreIT.java index 6cd76c8fd..c44953bc7 100644 --- a/vector-stores/spring-ai-typesense-store/src/test/java/org/springframework/ai/vectorstore/typesense/TypesenseVectorStoreIT.java +++ b/vector-stores/spring-ai-typesense-store/src/test/java/org/springframework/ai/vectorstore/typesense/TypesenseVectorStoreIT.java @@ -242,9 +242,7 @@ public class TypesenseVectorStoreIT { @Bean public VectorStore vectorStore(Client client, EmbeddingModel embeddingModel) { - return TypesenseVectorStore.builder() - .client(client) - .embeddingModel(embeddingModel) + return TypesenseVectorStore.builder(client, embeddingModel) .collectionName("test_vector_store") .embeddingDimension(embeddingModel.dimensions()) .initializeSchema(true) diff --git a/vector-stores/spring-ai-typesense-store/src/test/java/org/springframework/ai/vectorstore/typesense/TypesenseVectorStoreObservationIT.java b/vector-stores/spring-ai-typesense-store/src/test/java/org/springframework/ai/vectorstore/typesense/TypesenseVectorStoreObservationIT.java index 86223036c..e94d76d2a 100644 --- a/vector-stores/spring-ai-typesense-store/src/test/java/org/springframework/ai/vectorstore/typesense/TypesenseVectorStoreObservationIT.java +++ b/vector-stores/spring-ai-typesense-store/src/test/java/org/springframework/ai/vectorstore/typesense/TypesenseVectorStoreObservationIT.java @@ -170,9 +170,7 @@ public class TypesenseVectorStoreObservationIT { public VectorStore vectorStore(Client client, EmbeddingModel embeddingModel, ObservationRegistry observationRegistry) { - return TypesenseVectorStore.builder() - .client(client) - .embeddingModel(embeddingModel) + return TypesenseVectorStore.builder(client, embeddingModel) .collectionName(TEST_COLLECTION_NAME) .embeddingDimension(embeddingModel.dimensions()) .initializeSchema(true) diff --git a/vector-stores/spring-ai-weaviate-store/src/main/java/org/springframework/ai/vectorstore/weaviate/WeaviateVectorStore.java b/vector-stores/spring-ai-weaviate-store/src/main/java/org/springframework/ai/vectorstore/weaviate/WeaviateVectorStore.java index 836450069..35e5814e0 100644 --- a/vector-stores/spring-ai-weaviate-store/src/main/java/org/springframework/ai/vectorstore/weaviate/WeaviateVectorStore.java +++ b/vector-stores/spring-ai-weaviate-store/src/main/java/org/springframework/ai/vectorstore/weaviate/WeaviateVectorStore.java @@ -181,9 +181,7 @@ public class WeaviateVectorStore extends AbstractObservationVectorStore { WeaviateClient weaviateClient, ObservationRegistry observationRegistry, VectorStoreObservationConvention customObservationConvention, BatchingStrategy batchingStrategy) { - this(builder().embeddingModel(embeddingModel) - .weaviateClient(weaviateClient) - .observationRegistry(observationRegistry) + this(builder(weaviateClient, embeddingModel).observationRegistry(observationRegistry) .customObservationConvention(customObservationConvention) .batchingStrategy(batchingStrategy)); } @@ -217,8 +215,8 @@ public class WeaviateVectorStore extends AbstractObservationVectorStore { * a WeaviateVectorStore. * @return a new WeaviateBuilder instance */ - public static WeaviateBuilder builder() { - return new WeaviateBuilder(); + public static WeaviateBuilder builder(WeaviateClient weaviateClient, EmbeddingModel embeddingModel) { + return new WeaviateBuilder(weaviateClient, embeddingModel); } private Field[] buildWeaviateSimilaritySearchFields() { @@ -550,10 +548,10 @@ public class WeaviateVectorStore extends AbstractObservationVectorStore { * @return this builder instance * @throws IllegalArgumentException if weaviateClient is null */ - public WeaviateBuilder weaviateClient(WeaviateClient weaviateClient) { - Assert.notNull(weaviateClient, "weaviateClient must not be null"); + private WeaviateBuilder(WeaviateClient weaviateClient, EmbeddingModel embeddingModel) { + super(embeddingModel); + Assert.notNull(weaviateClient, "WeaviateClient must not be null"); this.weaviateClient = weaviateClient; - return this; } /** @@ -612,7 +610,6 @@ public class WeaviateVectorStore extends AbstractObservationVectorStore { */ @Override public WeaviateVectorStore build() { - validate(); return new WeaviateVectorStore(this); } diff --git a/vector-stores/spring-ai-weaviate-store/src/test/java/org/springframework/ai/vectorstore/weaviate/WeaviateVectorStoreBuilderTests.java b/vector-stores/spring-ai-weaviate-store/src/test/java/org/springframework/ai/vectorstore/weaviate/WeaviateVectorStoreBuilderTests.java index 739ed525a..03986de31 100644 --- a/vector-stores/spring-ai-weaviate-store/src/test/java/org/springframework/ai/vectorstore/weaviate/WeaviateVectorStoreBuilderTests.java +++ b/vector-stores/spring-ai-weaviate-store/src/test/java/org/springframework/ai/vectorstore/weaviate/WeaviateVectorStoreBuilderTests.java @@ -47,10 +47,7 @@ class WeaviateVectorStoreBuilderTests { void shouldBuildWithMinimalConfiguration() { WeaviateClient weaviateClient = new WeaviateClient(new Config("http", "localhost:8080")); - WeaviateVectorStore vectorStore = WeaviateVectorStore.builder() - .weaviateClient(weaviateClient) - .embeddingModel(embeddingModel) - .build(); + WeaviateVectorStore vectorStore = WeaviateVectorStore.builder(weaviateClient, embeddingModel).build(); assertThat(vectorStore).isNotNull(); } @@ -59,9 +56,7 @@ class WeaviateVectorStoreBuilderTests { void shouldBuildWithCustomConfiguration() { WeaviateClient weaviateClient = new WeaviateClient(new Config("http", "localhost:8080")); - WeaviateVectorStore vectorStore = WeaviateVectorStore.builder() - .weaviateClient(weaviateClient) - .embeddingModel(embeddingModel) + WeaviateVectorStore vectorStore = WeaviateVectorStore.builder(weaviateClient, embeddingModel) .objectClass("CustomClass") .consistencyLevel(ConsistentLevel.QUORUM) .filterMetadataFields(List.of(MetadataField.text("country"), MetadataField.number("year"))) @@ -72,7 +67,7 @@ class WeaviateVectorStoreBuilderTests { @Test void shouldFailWithoutWeaviateClient() { - assertThatThrownBy(() -> WeaviateVectorStore.builder().embeddingModel(embeddingModel).build()) + assertThatThrownBy(() -> WeaviateVectorStore.builder(null, embeddingModel).build()) .isInstanceOf(IllegalArgumentException.class) .hasMessage("WeaviateClient must not be null"); } @@ -81,7 +76,7 @@ class WeaviateVectorStoreBuilderTests { void shouldFailWithoutEmbeddingModel() { WeaviateClient weaviateClient = new WeaviateClient(new Config("http", "localhost:8080")); - assertThatThrownBy(() -> WeaviateVectorStore.builder().weaviateClient(weaviateClient).build()) + assertThatThrownBy(() -> WeaviateVectorStore.builder(weaviateClient, null).build()) .isInstanceOf(IllegalArgumentException.class) .hasMessage("EmbeddingModel must be configured"); } @@ -90,33 +85,29 @@ class WeaviateVectorStoreBuilderTests { void shouldFailWithInvalidObjectClass() { WeaviateClient weaviateClient = new WeaviateClient(new Config("http", "localhost:8080")); - assertThatThrownBy(() -> WeaviateVectorStore.builder() - .weaviateClient(weaviateClient) - .embeddingModel(embeddingModel) - .objectClass("") - .build()).isInstanceOf(IllegalArgumentException.class).hasMessage("objectClass must not be empty"); + assertThatThrownBy(() -> WeaviateVectorStore.builder(weaviateClient, embeddingModel).objectClass("").build()) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("objectClass must not be empty"); } @Test void shouldFailWithNullConsistencyLevel() { WeaviateClient weaviateClient = new WeaviateClient(new Config("http", "localhost:8080")); - assertThatThrownBy(() -> WeaviateVectorStore.builder() - .weaviateClient(weaviateClient) - .embeddingModel(embeddingModel) - .consistencyLevel(null) - .build()).isInstanceOf(IllegalArgumentException.class).hasMessage("consistencyLevel must not be null"); + assertThatThrownBy( + () -> WeaviateVectorStore.builder(weaviateClient, embeddingModel).consistencyLevel(null).build()) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("consistencyLevel must not be null"); } @Test void shouldFailWithNullFilterMetadataFields() { WeaviateClient weaviateClient = new WeaviateClient(new Config("http", "localhost:8080")); - assertThatThrownBy(() -> WeaviateVectorStore.builder() - .weaviateClient(weaviateClient) - .embeddingModel(embeddingModel) - .filterMetadataFields(null) - .build()).isInstanceOf(IllegalArgumentException.class).hasMessage("filterMetadataFields must not be null"); + assertThatThrownBy( + () -> WeaviateVectorStore.builder(weaviateClient, embeddingModel).filterMetadataFields(null).build()) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("filterMetadataFields must not be null"); } @Test diff --git a/vector-stores/spring-ai-weaviate-store/src/test/java/org/springframework/ai/vectorstore/weaviate/WeaviateVectorStoreIT.java b/vector-stores/spring-ai-weaviate-store/src/test/java/org/springframework/ai/vectorstore/weaviate/WeaviateVectorStoreIT.java index b675b5f96..28c45b721 100644 --- a/vector-stores/spring-ai-weaviate-store/src/test/java/org/springframework/ai/vectorstore/weaviate/WeaviateVectorStoreIT.java +++ b/vector-stores/spring-ai-weaviate-store/src/test/java/org/springframework/ai/vectorstore/weaviate/WeaviateVectorStoreIT.java @@ -252,9 +252,7 @@ public class WeaviateVectorStoreIT { WeaviateClient weaviateClient = new WeaviateClient( new Config("http", weaviateContainer.getHttpHostAddress())); - return WeaviateVectorStore.builder() - .weaviateClient(weaviateClient) - .embeddingModel(embeddingModel) + return WeaviateVectorStore.builder(weaviateClient, embeddingModel) .filterMetadataFields(List.of(WeaviateVectorStore.MetadataField.text("country"), WeaviateVectorStore.MetadataField.number("year"))) .consistencyLevel(WeaviateVectorStore.ConsistentLevel.ONE) diff --git a/vector-stores/spring-ai-weaviate-store/src/test/java/org/springframework/ai/vectorstore/weaviate/WeaviateVectorStoreObservationIT.java b/vector-stores/spring-ai-weaviate-store/src/test/java/org/springframework/ai/vectorstore/weaviate/WeaviateVectorStoreObservationIT.java index b3b8ea8f7..23f012491 100644 --- a/vector-stores/spring-ai-weaviate-store/src/test/java/org/springframework/ai/vectorstore/weaviate/WeaviateVectorStoreObservationIT.java +++ b/vector-stores/spring-ai-weaviate-store/src/test/java/org/springframework/ai/vectorstore/weaviate/WeaviateVectorStoreObservationIT.java @@ -166,9 +166,7 @@ public class WeaviateVectorStoreObservationIT { WeaviateClient weaviateClient = new WeaviateClient( new io.weaviate.client.Config("http", weaviateContainer.getHttpHostAddress())); - return WeaviateVectorStore.builder() - .weaviateClient(weaviateClient) - .embeddingModel(embeddingModel) + return WeaviateVectorStore.builder(weaviateClient, embeddingModel) .consistencyLevel(WeaviateVectorStore.ConsistentLevel.ONE) .observationRegistry(observationRegistry) .batchingStrategy(new TokenCountBatchingStrategy())