Add property to initialize schema for vector stores

* Default is fale
* Update docs
This commit is contained in:
Josh Long
2024-05-25 19:18:49 +02:00
committed by Mark Pollack
parent b872c894c3
commit 2d43e40024
68 changed files with 361 additions and 116 deletions

View File

@@ -12,6 +12,27 @@ For further information go to our [Spring AI reference documentation](https://do
On our march to release 1.0.0 M1 we have made several breaking changes. Apologies, it is for the best!
**(22.25.2024)**
Vector stores that have a schema are now *not* initialized by default.
As is the convention with other Spring projects that rely on a schema, you must opt into allowing Spring to create a schema for you.
A new configuration property named `initialize-schema` has been introduced, with `false` being the default value.
Check the documentation section for your vector store's configuration properties for the full syntax.
The following vector stores have been impacted by this change
* Azure AI Search
* Chroma
* Elasticsearch
* SAP Hana
* Milvus
* MongoDB
* Neo4j
* PGVector
* Pinecone
* Qdrant
* Redis
* Weaviate
**(22.05.2024)**
A major change was made that took the 'old' `ChatClient` and moved the functionality into `ChatModel`. The 'new' `ChatClient` now takes an instance of `ChatModel`. This was done do support a fluent API for creating and executing prompts in a style similar to other client classes in the Spring ecosystem, such as `RestClient`, `WebClient`, and `JdbcClient`. Refer to the [JavaDoc](https://docs.spring.io/spring-ai/docs/1.0.0-SNAPSHOT/api/) for more information on the Fluent API, proper reference documentation is coming shortly.

View File

@@ -105,13 +105,13 @@ public class OllamaEmbeddingModel extends AbstractEmbeddingModel {
List<List<Double>> embeddingList = new ArrayList<>();
for (String inputContent : request.getInstructions()) {
var ollamaEmbeddingRequest = ollamaEmbeddingRequest(inputContent, request.getOptions());
EmbeddingRequest ollamaEmbeddingRequest = ollamaEmbeddingRequest(inputContent, request.getOptions());
OllamaApi.EmbeddingResponse response = this.ollamaApi.embeddings(ollamaEmbeddingRequest);
embeddingList.add(response.embedding());
}
var indexCounter = new AtomicInteger(0);
AtomicInteger indexCounter = new AtomicInteger(0);
List<Embedding> embeddings = embeddingList.stream()
.map(e -> new Embedding(e, indexCounter.getAndIncrement()))

View File

@@ -16,8 +16,6 @@
package org.springframework.ai.ollama;
import org.junit.jupiter.api.Test;
import org.springframework.ai.embedding.EmbeddingOptions;
import org.springframework.ai.ollama.api.OllamaApi;
import org.springframework.ai.ollama.api.OllamaOptions;
@@ -28,7 +26,7 @@ import static org.assertj.core.api.Assertions.assertThat;
*/
public class OllamaEmbeddingRequestTests {
OllamaEmbeddingModel chatModel = new OllamaEmbeddingModel(new OllamaApi()).withDefaultOptions(
OllamaEmbeddingModel chatModel = new OllamaEmbeddingModel(new OllamaApi(),
new OllamaOptions().withModel("DEFAULT_MODEL").withMainGPU(11).withUseMMap(true).withNumGPU(1));
@Test
@@ -46,9 +44,10 @@ public class OllamaEmbeddingRequestTests {
@Test
public void ollamaEmbeddingRequestRequestOptions() {
EmbeddingOptions promptOptions = new OllamaOptions().withModel("PROMPT_MODEL")
.withMainGPU(22)
.withUseMMap(true)
var promptOptions = new OllamaOptions()//
.withModel("PROMPT_MODEL")//
.withMainGPU(22)//
.withUseMMap(true)//
.withNumGPU(2);
var request = chatModel.ollamaEmbeddingRequest("Hello", promptOptions);

View File

@@ -78,7 +78,7 @@ import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class)
public class OpenAiRetryTests {
private class TestRetryListener implements RetryListener {
private static class TestRetryListener implements RetryListener {
int onErrorRetryCount = 0;

View File

@@ -89,7 +89,7 @@ public class ChatMemoryLongTermSystemPromptIT extends BaseMemoryTest {
QdrantClient qdrantClient = new QdrantClient(QdrantGrpcClient
.newBuilder(qdrantContainer.getHost(), qdrantContainer.getMappedPort(QDRANT_GRPC_PORT), false)
.build());
return new QdrantVectorStore(qdrantClient, COLLECTION_NAME, embeddingModel);
return new QdrantVectorStore(qdrantClient, COLLECTION_NAME, embeddingModel, true);
}
@Bean

View File

@@ -177,7 +177,7 @@ public class LongShortTermChatMemoryWithRagIT {
QdrantClient qdrantClient = new QdrantClient(QdrantGrpcClient
.newBuilder(qdrantContainer.getHost(), qdrantContainer.getMappedPort(QDRANT_GRPC_PORT), false)
.build());
return new QdrantVectorStore(qdrantClient, COLLECTION_NAME, embeddingModel);
return new QdrantVectorStore(qdrantClient, COLLECTION_NAME, embeddingModel, true);
}
@Bean

View File

@@ -159,7 +159,7 @@ public class OpenAiPromptTransformingChatServiceIT {
QdrantClient qdrantClient = new QdrantClient(QdrantGrpcClient
.newBuilder(qdrantContainer.getHost(), qdrantContainer.getMappedPort(QDRANT_GRPC_PORT), false)
.build());
return new QdrantVectorStore(qdrantClient, COLLECTION_NAME, embeddingModel);
return new QdrantVectorStore(qdrantClient, COLLECTION_NAME, embeddingModel, true);
}
@Bean

View File

@@ -83,6 +83,13 @@ The `similaritySearch` methods in the interface allow for retrieving documents s
Find more information on the `Filter.Expression` in the <<metadata-filters>> section.
== Schema Initialization
Some vector stores require their backend schema to be initialized before usage.
It will not be initialized for you by default.
You must opt-in, by passing a `boolean` for the appropriate constructor argument or, if using Spring Boot, setting the appropriate `initialize-schema` property to `true` in `application.properties` or `application.yml`.
Check the documentation for the vector store you are using for the specific property name.
== Available Implementations
These are the available implementations of the `VectorStore` interface:

View File

@@ -15,10 +15,17 @@ SELECT content FROM table ORDER BY content_vector ANN OF query_embedding ;
More docs on this can be read https://cassandra.apache.org/doc/latest/cassandra/getting-started/vector-search-quickstart.html[here].
This Spring AI Vector Store is designed to work for both brand new RAG applications as well as being able to be retrofitted on top of existing data and tables.
This Spring AI Vector Store is designed to work for both brand-new RAG applications and be able to be retrofitted on top of existing data and tables.
The store can also be used for non-RAG use-cases in an existing database, e.g. semantic searches, geo-proximity searches, etc.
The vector store implementation can initialize the requisite schema for you, but you must opt-in by specifying the `initializeSchema` boolean in the appropriate constructor or by setting `...initialize-schema=true` in the `application.properties` file.
NOTE: this is a breaking change! In earlier versions of Spring AI, this schema initialization happened by default.
The store will automatically create, or enhance, the schema as needed according to its configuration. If you don't want the schema modifications, configure the store with `disallowSchemaChanges`.
== What is JVector ?

View File

@@ -12,7 +12,12 @@ link:https://azure.microsoft.com/en-us/products/ai-services/ai-search/[Azure AI
== Configuration
On startup, the AzureVectorStore will attempt to create a new index within your AI Search service instance. Alternatively, you can create the index manually.
On startup, the `AzureVectorStore` can attempt to create a new index within your AI Search service instance if you've opted in by setting the relevant `initializeSchema` `boolean` property to `true` in the constructor or, if using Spring Boot, setting `...initialize-schema=true` in your `application.properties` file.
NOTE: this is a breaking change! In earlier versions of Spring AI, this schema initialization happened by default.
Alternatively, you can create the index manually.
To set up an AzureVectorStore, you will need the settings retrieved from the prerequisites above along with your index name:

View File

@@ -15,7 +15,7 @@ On startup, the `ChromaVectorStore` creates the required collection if one is no
== Auto-configuration
Spring AI provides Spring Boot auto-configuration for the Chroma Vector Sore.
Spring AI provides Spring Boot auto-configuration for the Chroma Vector Store.
To enable it, add the following dependency to your project's Maven `pom.xml` file:
[source, xml]
@@ -39,6 +39,14 @@ TIP: Refer to the xref:getting-started.adoc#dependency-management[Dependency Man
TIP: Refer to the xref:getting-started.adoc#repositories[Repositories] section to add Milestone and/or Snapshot Repositories to your build file.
The vector store implementation can initialize the requisite schema for you, but you must opt-in by specifying the `initializeSchema` boolean in the appropriate constructor or by setting `...initialize-schema=true` in the `application.properties` file.
NOTE: this is a breaking change! In earlier versions of Spring AI, this schema initialization happened by default.
Additionally, you will need a configured `EmbeddingModel` bean. Refer to the xref:api/embeddings.adoc#available-implementations[EmbeddingModel] section for more information.
Here is an example of the needed bean:
@@ -58,6 +66,7 @@ A simple configuration can either be provided via Spring Boot's _application.pro
[source,properties]
----
# Chroma Vector Store connection properties
spring.ai.vectorstore.chroma.client.initialize-schema=<true or false>
spring.ai.vectorstore.chroma.client.host=<your Chroma instance host>
spring.ai.vectorstore.chroma.client.port=<your Chroma instance port>
spring.ai.vectorstore.chroma.client.key-token=<your access token (if configure)>
@@ -75,7 +84,7 @@ spring.ai.openai.api.key=<OpenAI Api-key>
Please have a look at the list of xref:#_configuration_properties[configuration parameters] for the vector store to learn about the default values and configuration options.
Now you can Auto-wire the Chroma Vector Store in your application and use it
Now you can auto-wire the Chroma Vector Store in your application and use it
[source,java]
----

View File

@@ -39,6 +39,14 @@ TIP: Refer to the xref:getting-started.adoc#dependency-management[Dependency Man
TIP: Refer to the xref:getting-started.adoc#repositories[Repositories] section to add Milestone and/or Snapshot Repositories to your build file.
The vector store implementation can initialize the requisite schema for you, but you must opt-in by specifying the `initializeSchema` boolean in the appropriate constructor or by setting `...initialize-schema=true` in the `application.properties` file.
NOTE: this is a breaking change! In earlier versions of Spring AI, this schema initialization happened by default.
Please have a look at the list of <<elasticsearchvector-properties,configuration parameters>> for the vector store to learn about the default values and configuration options.
Additionally, you will need a configured `EmbeddingModel` bean. Refer to the xref:api/embeddings.adoc#available-implementations[EmbeddingModel] section for more information.
@@ -128,6 +136,7 @@ Properties starting with the `spring.ai.vectorstore.elasticsearch.*` prefix are
|`spring.ai.vectorstore.elasticsearch.dimensions` | The number of dimensions in the vector. | 1536
|`spring.ai.vectorstore.elasticsearch.dense-vector-indexing` | Whether to use dense vector indexing. | true
|`spring.ai.vectorstore.elasticsearch.similarity` | The similarity function to use. | `cosine`
|`spring.ai.vectorstore.elasticsearch.initialize-schema`| whether to initialize the required schema | `false`
|===
== Metadata Filtering

View File

@@ -8,7 +8,7 @@
== Auto-configuration
Spring AI provides Spring Boot auto-configuration for the SAP Hana Vector Sore.
Spring AI provides Spring Boot auto-configuration for the SAP Hana Vector Store.
To enable it, add the following dependency to your project's Maven `pom.xml` file:
[source, xml]
@@ -50,6 +50,7 @@ It uses `spring.datasource.*` properties to configure the Hana datasource and th
|`spring.datasource.password` | Hana datasource password | -
|`spring.ai.vectorstore.hanadb.top-k`| TODO | -
|`spring.ai.vectorstore.hanadb.table-name`| TODO | -
|`spring.ai.vectorstore.hanadb.initialize-schema`| whether to initialize the required schema | `false`
|===

View File

@@ -30,12 +30,21 @@ dependencies {
}
----
The Vector Store, also requires an `EmbeddingModel` instance to calculate embeddings for the documents.
You can pick one of the available xref:api/embeddings.adoc#available-implementations[EmbeddingModel Implementations].
TIP: Refer to the xref:getting-started.adoc#dependency-management[Dependency Management] section to add the Spring AI BOM to your build file.
Refer to the xref:getting-started.adoc#repositories[Repositories] section to add Milestone and/or Snapshot Repositories to your build file.
The vector store implementation can initialize the requisite schema for you, but you must opt-in by specifying the `initializeSchema` boolean in the appropriate constructor or by setting `...initialize-schema=true` in the `application.properties` file.
NOTE: this is a breaking change! In earlier versions of Spring AI, this schema initialization happened by default.
The Vector Store, also requires an `EmbeddingModel` instance to calculate embeddings for the documents.
You can pick one of the available xref:api/embeddings.adoc#available-implementations[EmbeddingModel Implementations].
To connect to and configure the `MilvusVectorStore`, you need to provide access details for your instance.
A simple configuration can either be provided via Spring Boot's `application.yml`
@@ -162,6 +171,7 @@ You can use the following properties in your Spring Boot configuration to custom
|spring.ai.vectorstore.milvus.database-name | The name of the Milvus database to use. | default
|spring.ai.vectorstore.milvus.collection-name | Milvus collection name to store the vectors | vector_store
|spring.ai.vectorstore.milvus.initialize-schema | whether to initialize Milvus' backend | false
|spring.ai.vectorstore.milvus.embedding-dimension | The dimension of the vectors to be stored in the Milvus collection. | 1536
|spring.ai.vectorstore.milvus.index-type | The type of the index to be created for the Milvus collection. | IVF_FLAT
|spring.ai.vectorstore.milvus.metric-type | The metric type to be used for the Milvus collection. | COSINE

View File

@@ -10,7 +10,7 @@ TODO: Add prerequisites instructions
== Auto-configuration
Spring AI provides Spring Boot auto-configuration for the MongoDB Atlas Vector Sore.
Spring AI provides Spring Boot auto-configuration for the MongoDB Atlas Vector Store.
To enable it, add the following dependency to your project's Maven `pom.xml` file:
[source, xml]
@@ -34,6 +34,16 @@ TIP: Refer to the xref:getting-started.adoc#dependency-management[Dependency Man
TIP: Refer to the xref:getting-started.adoc#repositories[Repositories] section to add Milestone and/or Snapshot Repositories to your build file.
The vector store implementation can initialize the requisite schema for you, but you must opt-in by specifying the `initializeSchema` boolean in the appropriate constructor or by setting `...initialize-schema=true` in the `application.properties` file.
NOTE: this is a breaking change! In earlier versions of Spring AI, this schema initialization happened by default.
Additionally, you will need a configured `EmbeddingModel` bean. Refer to the xref:api/embeddings.adoc#available-implementations[EmbeddingModel] section for more information.
Here is an example of the needed bean:
@@ -88,6 +98,7 @@ You can use the following properties in your Spring Boot configuration to custom
|Property| Description | Default value
|`spring.ai.vectorstore.mongodb.collection-name`| The name of the collection to store the vectors. | `vector_store`
|`spring.ai.vectorstore.mongodb.initialize-schema`| whether to initialize the backend schema for you | `false`
|`spring.ai.vectorstore.mongodb.path-name`| The name of the path to store the vectors. | `embedding`
|`spring.ai.vectorstore.mongodb.indexName`| The name of the index to store the vectors. | `vector_index`
|===

View File

@@ -41,8 +41,16 @@ dependencies {
}
----
TIP: Refer to the xref:getting-started.adoc#dependency-management[Dependency Management] section to add the Spring AI BOM to your build file.
The vector store implementation can initialize the requisite schema for you, but you must opt-in by specifying the `initializeSchema` boolean in the appropriate constructor or by setting `...initialize-schema=true` in the `application.properties` file.
NOTE: this is a breaking change! In earlier versions of Spring AI, this schema initialization happened by default.
== Configuration
To connect to Neo4j and use the `Neo4jVectorStore`, you need to provide access details for your instance.
@@ -79,7 +87,7 @@ Spring Boot's auto-configuration feature for the Neo4j Driver will create a bean
== Auto-configuration
Spring AI provides Spring Boot auto-configuration for the Neo4j Vector Sore.
Spring AI provides Spring Boot auto-configuration for the Neo4j Vector Store.
To enable it, add the following dependency to your project's Maven `pom.xml` file:
[source, xml]
@@ -185,6 +193,7 @@ You can use the following properties in your Spring Boot configuration to custom
|Property|Default value
|`spring.ai.vectorstore.neo4j.database-name`|neo4j
|`spring.ai.vectorstore.neo4j.initialize-schema`|false
|`spring.ai.vectorstore.neo4j.embedding-dimension`|1536
|`spring.ai.vectorstore.neo4j.distance-type`|cosine
|`spring.ai.vectorstore.neo4j.label`|Document

View File

@@ -55,6 +55,11 @@ dependencies {
}
----
The vector store implementation can initialize the requisite schema for you, but you must opt-in by specifying the `initializeSchema` boolean in the appropriate constructor or by setting `...initialize-schema=true` in the `application.properties` file.
NOTE: this is a breaking change! In earlier versions of Spring AI, this schema initialization happened by default.
The Vector Store, also requires an `EmbeddingModel` instance to calculate embeddings for the documents.
You can pick one of the available xref:api/embeddings.adoc#available-implementations[EmbeddingModel Implementations].
@@ -133,6 +138,7 @@ You can use the following properties in your Spring Boot configuration to custom
|`spring.ai.vectorstore.pgvector.distance-type`| Search distance type. Defaults to `COSINE_DISTANCE`. But if vectors are normalized to length 1, you can use `EUCLIDEAN_DISTANCE` or `NEGATIVE_INNER_PRODUCT` for best performance.| COSINE_DISTANCE
|`spring.ai.vectorstore.pgvector.dimensions`| Embeddings dimension. If not specified explicitly the PgVectorStore will retrieve the dimensions form the provided `EmbeddingModel`. Dimensions are set to the embedding column the on table creation. If you change the dimensions your would have to re-create the vector_store table as well. | -
|`spring.ai.vectorstore.pgvector.remove-existing-vector-store-table` | Deletes the existing `vector_store` table on start up. | false
|`spring.ai.vectorstore.pgvector.initialize-schema` | Whether to initialize the required schema | false
|===

View File

@@ -26,7 +26,7 @@ This information is available to you in the Pinecone UI portal.
== Auto-configuration
Spring AI provides Spring Boot auto-configuration for the Pinecone Vector Sore.
Spring AI provides Spring Boot auto-configuration for the Pinecone Vector Store.
To enable it, add the following dependency to your project's Maven `pom.xml` file:
[source, xml]

View File

@@ -35,6 +35,11 @@ dependencies {
}
----
The vector store implementation can initialize the requisite schema for you, but you must opt-in by specifying the `initializeSchema` boolean in the appropriate constructor or by setting `...initialize-schema=true` in the `application.properties` file.
NOTE: this is a breaking change! In earlier versions of Spring AI, this schema initialization happened by default.
The Vector Store, also requires an `EmbeddingModel` instance to calculate embeddings for the documents.
You can pick one of the available xref:api/embeddings.adoc#available-implementations[EmbeddingModel Implementations].
@@ -110,6 +115,7 @@ You can use the following properties in your Spring Boot configuration to custom
|`spring.ai.vectorstore.qdrant.api-key`| The API key to use for authentication with the Qdrant server. | -
|`spring.ai.vectorstore.qdrant.collection-name`| The name of the collection to use in Qdrant. | -
|`spring.ai.vectorstore.qdrant.use-tls`| Whether to use TLS(HTTPS). | false
|`spring.ai.vectorstore.qdrant.initialize-schema`| Whether to initialize the backend schema or not | false
|===
== Metadata filtering

View File

@@ -21,7 +21,7 @@ link:https://redis.io/docs/interact/search-and-query/[Redis Search and Query] ex
== Auto-configuration
Spring AI provides Spring Boot auto-configuration for the Redis Vector Sore.
Spring AI provides Spring Boot auto-configuration for the Redis Vector Store.
To enable it, add the following dependency to your project's Maven `pom.xml` file:
[source, xml]
@@ -45,6 +45,12 @@ TIP: Refer to the xref:getting-started.adoc#dependency-management[Dependency Man
TIP: Refer to the xref:getting-started.adoc#repositories[Repositories] section to add Milestone and/or Snapshot Repositories to your build file.
The vector store implementation can initialize the requisite schema for you, but you must opt-in by specifying the `initializeSchema` boolean in the appropriate constructor or by setting `...initialize-schema=true` in the `application.properties` file.
NOTE: this is a breaking change! In earlier versions of Spring AI, this schema initialization happened by default.
Additionally, you will need a configured `EmbeddingModel` bean. Refer to the xref:api/embeddings.adoc#available-implementations[EmbeddingModel] section for more information.
Here is an example of the needed bean:
@@ -102,6 +108,7 @@ You can use the following properties in your Spring Boot configuration to custom
|`spring.ai.vectorstore.redis.uri`| Server connection URI | `redis://localhost:6379`
|`spring.ai.vectorstore.redis.index`| Index name | `default-index`
|`spring.ai.vectorstore.redis.initialize-schema`| whether to initialize the required schema | `false`
|`spring.ai.vectorstore.redis.prefix`| Prefix | `default:`
|===

View File

@@ -40,6 +40,11 @@ dependencies {
}
----
The vector store implementation can initialize the requisite schema for you, but you must opt-in by specifying the `initializeSchema` boolean in the appropriate constructor or by setting `...initialize-schema=true` in the `application.properties` file.
NOTE: this is a breaking change! In earlier versions of Spring AI, this schema initialization happened by default.
The Vector Store, also requires an `EmbeddingModel` instance to calculate embeddings for the documents.
You can pick one of the available xref:api/embeddings.adoc#available-implementations[EmbeddingModel Implementations].
@@ -116,6 +121,7 @@ You can use the following properties in your Spring Boot configuration to custom
|`spring.ai.vectorstore.weaviate.consistency-level`| Desired tradeoff between consistency and speed | ConsistentLevel.ONE
|`spring.ai.vectorstore.weaviate.filter-field`| spring.ai.vectorstore.weaviate.filter-field.<field-name>=<field-type> | -
|`spring.ai.vectorstore.weaviate.headers`| | -
|`spring.ai.vectorstore.weaviate.initialize-schema`| Whether to initialize the required schema | `false`
|===
== Metadata filtering

View File

@@ -0,0 +1,18 @@
package org.springframework.ai.autoconfigure;
/**
* @author Josh Long
*/
public class CommonVectorStoreProperties {
private boolean initializeSchema = false;
public boolean isInitializeSchema() {
return initializeSchema;
}
public void setInitializeSchema(boolean initializeSchema) {
this.initializeSchema = initializeSchema;
}
}

View File

@@ -50,7 +50,7 @@ public class AzureVectorStoreAutoConfiguration {
public AzureVectorStore vectorStore(SearchIndexClient searchIndexClient, EmbeddingModel embeddingModel,
AzureVectorStoreProperties properties) {
var vectorStore = new AzureVectorStore(searchIndexClient, embeddingModel);
var vectorStore = new AzureVectorStore(searchIndexClient, embeddingModel, properties.isInitializeSchema());
vectorStore.setIndexName(properties.getIndexName());

View File

@@ -15,6 +15,7 @@
*/
package org.springframework.ai.autoconfigure.vectorstore.azure;
import org.springframework.ai.autoconfigure.CommonVectorStoreProperties;
import org.springframework.ai.vectorstore.azure.AzureVectorStore;
import org.springframework.boot.context.properties.ConfigurationProperties;
@@ -22,7 +23,7 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
* @author Christian Tzolov
*/
@ConfigurationProperties(AzureVectorStoreProperties.CONFIG_PREFIX)
public class AzureVectorStoreProperties {
public class AzureVectorStoreProperties extends CommonVectorStoreProperties {
public static final String CONFIG_PREFIX = "spring.ai.vectorstore.azure";

View File

@@ -72,7 +72,8 @@ public class ChromaVectorStoreAutoConfiguration {
@ConditionalOnMissingBean
public ChromaVectorStore vectorStore(EmbeddingModel embeddingModel, ChromaApi chromaApi,
ChromaVectorStoreProperties storeProperties) {
return new ChromaVectorStore(embeddingModel, chromaApi, storeProperties.getCollectionName());
return new ChromaVectorStore(embeddingModel, chromaApi, storeProperties.getCollectionName(),
storeProperties.isInitializeSchema());
}
private static class PropertiesChromaConnectionDetails implements ChromaConnectionDetails {

View File

@@ -15,6 +15,7 @@
*/
package org.springframework.ai.autoconfigure.vectorstore.chroma;
import org.springframework.ai.autoconfigure.CommonVectorStoreProperties;
import org.springframework.ai.vectorstore.ChromaVectorStore;
import org.springframework.boot.context.properties.ConfigurationProperties;
@@ -22,7 +23,7 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
* @author Christian Tzolov
*/
@ConfigurationProperties(ChromaVectorStoreProperties.CONFIG_PREFIX)
public class ChromaVectorStoreProperties {
public class ChromaVectorStoreProperties extends CommonVectorStoreProperties {
public static final String CONFIG_PREFIX = "spring.ai.vectorstore.chroma.store";

View File

@@ -31,6 +31,7 @@ import org.springframework.util.StringUtils;
/**
* @author Eddú Meléndez
* @author Wei Jiang
* @author Josh Long
* @since 1.0.0
*/
@@ -58,7 +59,8 @@ class ElasticsearchVectorStoreAutoConfiguration {
elasticsearchVectorStoreOptions.setSimilarity(properties.getSimilarity());
}
return new ElasticsearchVectorStore(elasticsearchVectorStoreOptions, restClient, embeddingModel);
return new ElasticsearchVectorStore(elasticsearchVectorStoreOptions, restClient, embeddingModel,
properties.isInitializeSchema());
}
}

View File

@@ -15,15 +15,17 @@
*/
package org.springframework.ai.autoconfigure.vectorstore.elasticsearch;
import org.springframework.ai.autoconfigure.CommonVectorStoreProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* @author Eddú Meléndez
* @author Wei Jiang
* @author Josh Long
* @since 1.0.0
*/
@ConfigurationProperties(prefix = "spring.ai.vectorstore.elasticsearch")
public class ElasticsearchVectorStoreProperties {
public class ElasticsearchVectorStoreProperties extends CommonVectorStoreProperties {
/**
* The name of the index to store the vectors.

View File

@@ -62,7 +62,7 @@ public class MilvusVectorStoreAutoConfiguration {
.withEmbeddingDimension(properties.getEmbeddingDimension())
.build();
return new MilvusVectorStore(milvusClient, embeddingModel, config);
return new MilvusVectorStore(milvusClient, embeddingModel, config, properties.isInitializeSchema());
}
@Bean

View File

@@ -15,6 +15,7 @@
*/
package org.springframework.ai.autoconfigure.vectorstore.milvus;
import org.springframework.ai.autoconfigure.CommonVectorStoreProperties;
import org.springframework.ai.vectorstore.MilvusVectorStore;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.util.Assert;
@@ -23,7 +24,7 @@ import org.springframework.util.Assert;
* @author Christian Tzolov
*/
@ConfigurationProperties(MilvusVectorStoreProperties.CONFIG_PREFIX)
public class MilvusVectorStoreProperties {
public class MilvusVectorStoreProperties extends CommonVectorStoreProperties {
public static final String CONFIG_PREFIX = "spring.ai.vectorstore.milvus";

View File

@@ -54,7 +54,7 @@ public class MongoDBAtlasVectorStoreAutoConfiguration {
}
MongoDBAtlasVectorStore.MongoDBVectorStoreConfig config = builder.build();
return new MongoDBAtlasVectorStore(mongoTemplate, embeddingModel, config);
return new MongoDBAtlasVectorStore(mongoTemplate, embeddingModel, config, properties.isInitializeSchema());
}
}

View File

@@ -15,6 +15,7 @@
*/
package org.springframework.ai.autoconfigure.vectorstore.mongo;
import org.springframework.ai.autoconfigure.CommonVectorStoreProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
@@ -23,7 +24,7 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
* @since 1.0.0
*/
@ConfigurationProperties(MongoDBAtlasVectorStoreProperties.CONFIG_PREFIX)
public class MongoDBAtlasVectorStoreProperties {
public class MongoDBAtlasVectorStoreProperties extends CommonVectorStoreProperties {
public static final String CONFIG_PREFIX = "spring.ai.vectorstore.mongodb";

View File

@@ -28,6 +28,7 @@ import org.springframework.context.annotation.Bean;
/**
* @author Jingzhou Ou
* @author Josh Long
*/
@AutoConfiguration(after = Neo4jAutoConfiguration.class)
@ConditionalOnClass({ Neo4jVectorStore.class, EmbeddingModel.class, Driver.class })
@@ -49,7 +50,7 @@ public class Neo4jVectorStoreAutoConfiguration {
.withConstraintName(properties.getConstraintName())
.build();
return new Neo4jVectorStore(driver, embeddingModel, config);
return new Neo4jVectorStore(driver, embeddingModel, config, properties.isInitializeSchema());
}
}

View File

@@ -15,14 +15,16 @@
*/
package org.springframework.ai.autoconfigure.vectorstore.neo4j;
import org.springframework.ai.autoconfigure.CommonVectorStoreProperties;
import org.springframework.ai.vectorstore.Neo4jVectorStore;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* @author Jingzhou Ou
* @author Josh Long
*/
@ConfigurationProperties(Neo4jVectorStoreProperties.CONFIG_PREFIX)
public class Neo4jVectorStoreProperties {
public class Neo4jVectorStoreProperties extends CommonVectorStoreProperties {
public static final String CONFIG_PREFIX = "spring.ai.vectorstore.neo4j";

View File

@@ -19,6 +19,7 @@ import javax.sql.DataSource;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.vectorstore.PgVectorStore;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
@@ -29,6 +30,7 @@ import org.springframework.jdbc.core.JdbcTemplate;
/**
* @author Christian Tzolov
* @author Josh Long
*/
@AutoConfiguration(after = JdbcTemplateAutoConfiguration.class)
@ConditionalOnClass({ PgVectorStore.class, DataSource.class, JdbcTemplate.class })
@@ -39,9 +41,9 @@ public class PgVectorStoreAutoConfiguration {
@ConditionalOnMissingBean
public PgVectorStore vectorStore(JdbcTemplate jdbcTemplate, EmbeddingModel embeddingModel,
PgVectorStoreProperties properties) {
var initializeSchema = properties.isInitializeSchema();
return new PgVectorStore(jdbcTemplate, embeddingModel, properties.getDimensions(), properties.getDistanceType(),
properties.isRemoveExistingVectorStoreTable(), properties.getIndexType());
properties.isRemoveExistingVectorStoreTable(), properties.getIndexType(), initializeSchema);
}
}

View File

@@ -15,6 +15,7 @@
*/
package org.springframework.ai.autoconfigure.vectorstore.pgvector;
import org.springframework.ai.autoconfigure.CommonVectorStoreProperties;
import org.springframework.ai.vectorstore.PgVectorStore;
import org.springframework.ai.vectorstore.PgVectorStore.PgDistanceType;
import org.springframework.ai.vectorstore.PgVectorStore.PgIndexType;
@@ -24,7 +25,7 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
* @author Christian Tzolov
*/
@ConfigurationProperties(PgVectorStoreProperties.CONFIG_PREFIX)
public class PgVectorStoreProperties {
public class PgVectorStoreProperties extends CommonVectorStoreProperties {
public static final String CONFIG_PREFIX = "spring.ai.vectorstore.pgvector";

View File

@@ -58,7 +58,8 @@ public class QdrantVectorStoreAutoConfiguration {
@ConditionalOnMissingBean
public QdrantVectorStore vectorStore(EmbeddingModel embeddingModel, QdrantVectorStoreProperties properties,
QdrantClient qdrantClient) {
return new QdrantVectorStore(qdrantClient, properties.getCollectionName(), embeddingModel);
return new QdrantVectorStore(qdrantClient, properties.getCollectionName(), embeddingModel,
properties.isInitializeSchema());
}
static class PropertiesQdrantConnectionDetails implements QdrantConnectionDetails {

View File

@@ -15,15 +15,17 @@
*/
package org.springframework.ai.autoconfigure.vectorstore.qdrant;
import org.springframework.ai.autoconfigure.CommonVectorStoreProperties;
import org.springframework.ai.vectorstore.qdrant.QdrantVectorStore;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* @author Anush Shetty
* @author Josh Long
* @since 0.8.1
*/
@ConfigurationProperties(QdrantVectorStoreProperties.CONFIG_PREFIX)
public class QdrantVectorStoreProperties {
public class QdrantVectorStoreProperties extends CommonVectorStoreProperties {
public static final String CONFIG_PREFIX = "spring.ai.vectorstore.qdrant";

View File

@@ -50,7 +50,7 @@ public class RedisVectorStoreAutoConfiguration {
.withPrefix(properties.getPrefix())
.build();
return new RedisVectorStore(config, embeddingModel);
return new RedisVectorStore(config, embeddingModel, properties.isInitializeSchema());
}
private static class PropertiesRedisConnectionDetails implements RedisConnectionDetails {

View File

@@ -15,13 +15,14 @@
*/
package org.springframework.ai.autoconfigure.vectorstore.redis;
import org.springframework.ai.autoconfigure.CommonVectorStoreProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* @author Julien Ruaux
*/
@ConfigurationProperties(RedisVectorStoreProperties.CONFIG_PREFIX)
public class RedisVectorStoreProperties {
public class RedisVectorStoreProperties extends CommonVectorStoreProperties {
public static final String CONFIG_PREFIX = "spring.ai.vectorstore.redis";

View File

@@ -72,7 +72,8 @@ public class WeaviateVectorStoreAutoConfiguration {
.toList())
.withConsistencyLevel(properties.getConsistencyLevel());
return new WeaviateVectorStore(configBuilder.build(), embeddingModel, weaviateClient);
return new WeaviateVectorStore(configBuilder.build(), embeddingModel, weaviateClient,
properties.isInitializeSchema());
}
static class PropertiesWeaviateConnectionDetails implements WeaviateConnectionDetails {

View File

@@ -17,6 +17,7 @@ package org.springframework.ai.autoconfigure.vectorstore.weaviate;
import java.util.Map;
import org.springframework.ai.autoconfigure.CommonVectorStoreProperties;
import org.springframework.ai.vectorstore.WeaviateVectorStore.WeaviateVectorStoreConfig;
import org.springframework.ai.vectorstore.WeaviateVectorStore.WeaviateVectorStoreConfig.ConsistentLevel;
import org.springframework.ai.vectorstore.WeaviateVectorStore.WeaviateVectorStoreConfig.MetadataField;
@@ -26,7 +27,7 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
* @author Christian Tzolov
*/
@ConfigurationProperties(WeaviateVectorStoreProperties.CONFIG_PREFIX)
public class WeaviateVectorStoreProperties {
public class WeaviateVectorStoreProperties extends CommonVectorStoreProperties {
public static final String CONFIG_PREFIX = "spring.ai.vectorstore.weaviate";

View File

@@ -151,6 +151,12 @@
<groupId>org.testcontainers</groupId>
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>com.vaadin.external.google</groupId>
<artifactId>android-json</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>

View File

@@ -15,13 +15,6 @@
*/
package org.springframework.ai.vectorstore.azure;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.TypeReference;
import com.azure.core.util.Context;
@@ -43,7 +36,6 @@ import com.azure.search.documents.models.VectorSearchOptions;
import com.azure.search.documents.models.VectorizedQuery;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ai.document.Document;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.vectorstore.SearchRequest;
@@ -54,6 +46,13 @@ import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
/**
* Uses Azure Cognitive Search as a backing vector store. Documents can be preloaded into
* a Cognitive Search index and managed via Azure tools or added and managed through this
@@ -63,6 +62,7 @@ import org.springframework.util.StringUtils;
* @author Greg Meyer
* @author Xiangyang Yu
* @author Christian Tzolov
* @author Josh Long
*/
public class AzureVectorStore implements VectorStore, InitializingBean {
@@ -104,12 +104,14 @@ public class AzureVectorStore implements VectorStore, InitializingBean {
private String indexName = DEFAULT_INDEX_NAME;
private final boolean initializeSchema;
/**
* List of metadata fields (as field name and type) that can be used in similarity
* search query filter expressions. The {@link Document#getMetadata()} can contain
* arbitrary number of metadata entries, but only the fields listed here can be used
* in the search filter expressions.
*
* <p>
* If new entries are added ot the filterMetadataFields the affected documents must be
* (re)updated.
*/
@@ -148,8 +150,9 @@ public class AzureVectorStore implements VectorStore, InitializingBean {
* for Azure search indexes and factory for {@link SearchClient}.
* @param embeddingModel The client for embedding operations.
*/
public AzureVectorStore(SearchIndexClient searchIndexClient, EmbeddingModel embeddingModel) {
this(searchIndexClient, embeddingModel, List.of());
public AzureVectorStore(SearchIndexClient searchIndexClient, EmbeddingModel embeddingModel,
boolean initializeSchema) {
this(searchIndexClient, embeddingModel, initializeSchema, List.of());
}
/**
@@ -161,12 +164,13 @@ public class AzureVectorStore implements VectorStore, InitializingBean {
* can be used in similarity search query filter expressions.
*/
public AzureVectorStore(SearchIndexClient searchIndexClient, EmbeddingModel embeddingModel,
List<MetadataField> filterMetadataFields) {
boolean initializeSchema, List<MetadataField> filterMetadataFields) {
Assert.notNull(embeddingModel, "The embedding model can not be null.");
Assert.notNull(searchIndexClient, "The search index client can not be null.");
Assert.notNull(filterMetadataFields, "The filterMetadataFields can not be null.");
this.initializeSchema = initializeSchema;
this.searchIndexClient = searchIndexClient;
this.embeddingModel = embeddingModel;
this.filterMetadataFields = filterMetadataFields;
@@ -328,6 +332,9 @@ public class AzureVectorStore implements VectorStore, InitializingBean {
@Override
public void afterPropertiesSet() throws Exception {
if (!this.initializeSchema)
return;
int dimensions = this.embeddingModel.dimensions();
List<SearchField> fields = new ArrayList<>();

View File

@@ -305,7 +305,7 @@ public class AzureVectorStoreIT {
public VectorStore vectorStore(SearchIndexClient searchIndexClient, EmbeddingModel embeddingModel) {
var filterableMetaFields = List.of(MetadataField.text("country"), MetadataField.int64("year"),
MetadataField.date("activationDate"));
return new AzureVectorStore(searchIndexClient, embeddingModel, filterableMetaFields);
return new AzureVectorStore(searchIndexClient, embeddingModel, true, filterableMetaFields);
}
@Bean

View File

@@ -34,7 +34,6 @@ import org.springframework.ai.document.Document;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.vectorstore.CassandraVectorStoreConfig.SchemaColumn;
import org.springframework.ai.vectorstore.filter.FilterExpressionConverter;
import org.springframework.beans.factory.InitializingBean;
import java.util.ArrayList;
import java.util.HashMap;
@@ -89,7 +88,7 @@ import java.util.concurrent.ConcurrentMap;
* @see EmbeddingModel
* @since 1.0.0
*/
public class CassandraVectorStore implements VectorStore, InitializingBean, AutoCloseable {
public class CassandraVectorStore implements VectorStore, AutoCloseable {
/**
* Indexes are automatically created with COSINE. This can be changed manually via
@@ -246,10 +245,6 @@ public class CassandraVectorStore implements VectorStore, InitializingBean, Auto
return documents;
}
@Override
public void afterPropertiesSet() {
}
@Override
public void close() throws Exception {
this.conf.close();

View File

@@ -61,14 +61,18 @@ public class ChromaVectorStore implements VectorStore, InitializingBean {
private String collectionId;
public ChromaVectorStore(EmbeddingModel embeddingModel, ChromaApi chromaApi) {
this(embeddingModel, chromaApi, DEFAULT_COLLECTION_NAME);
private final boolean initializeSchema;
public ChromaVectorStore(EmbeddingModel embeddingModel, ChromaApi chromaApi, boolean initializeSchema) {
this(embeddingModel, chromaApi, DEFAULT_COLLECTION_NAME, initializeSchema);
}
public ChromaVectorStore(EmbeddingModel embeddingModel, ChromaApi chromaApi, String collectionName) {
public ChromaVectorStore(EmbeddingModel embeddingModel, ChromaApi chromaApi, String collectionName,
boolean initializeSchema) {
this.embeddingModel = embeddingModel;
this.chromaApi = chromaApi;
this.collectionName = collectionName;
this.initializeSchema = initializeSchema;
this.filterExpressionConverter = new ChromaFilterExpressionConverter();
}
@@ -148,6 +152,10 @@ public class ChromaVectorStore implements VectorStore, InitializingBean {
@Override
public void afterPropertiesSet() throws Exception {
if (!this.initializeSchema)
return;
var collection = this.chromaApi.getCollection(this.collectionName);
if (collection == null) {
collection = this.chromaApi.createCollection(new ChromaApi.CreateCollectionRequest(this.collectionName));

View File

@@ -108,7 +108,7 @@ public class BasicAuthChromaWhereIT {
@Bean
public VectorStore chromaVectorStore(EmbeddingModel embeddingModel, ChromaApi chromaApi) {
return new ChromaVectorStore(embeddingModel, chromaApi, "TestCollection");
return new ChromaVectorStore(embeddingModel, chromaApi, "TestCollection", true);
}
@Bean

View File

@@ -213,7 +213,7 @@ public class ChromaVectorStoreIT {
@Bean
public VectorStore chromaVectorStore(EmbeddingModel embeddingModel, ChromaApi chromaApi) {
return new ChromaVectorStore(embeddingModel, chromaApi, "TestCollection");
return new ChromaVectorStore(embeddingModel, chromaApi, "TestCollection", true);
}
@Bean

View File

@@ -140,7 +140,7 @@ public class TokenSecuredChromaWhereIT {
@Bean
public VectorStore chromaVectorStore(EmbeddingModel embeddingModel, ChromaApi chromaApi) {
return new ChromaVectorStore(embeddingModel, chromaApi, "TestCollection");
return new ChromaVectorStore(embeddingModel, chromaApi, "TestCollection", true);
}
@Bean

View File

@@ -68,12 +68,15 @@ public class ElasticsearchVectorStore implements VectorStore, InitializingBean {
private String similarityFunction;
public ElasticsearchVectorStore(RestClient restClient, EmbeddingModel embeddingModel) {
this(new ElasticsearchVectorStoreOptions(), restClient, embeddingModel);
private final boolean initializeSchema;
public ElasticsearchVectorStore(RestClient restClient, EmbeddingModel embeddingModel, boolean initializeSchema) {
this(new ElasticsearchVectorStoreOptions(), restClient, embeddingModel, initializeSchema);
}
public ElasticsearchVectorStore(ElasticsearchVectorStoreOptions options, RestClient restClient,
EmbeddingModel embeddingModel) {
EmbeddingModel embeddingModel, boolean initializeSchema) {
this.initializeSchema = initializeSchema;
Objects.requireNonNull(embeddingModel, "RestClient must not be null");
Objects.requireNonNull(embeddingModel, "EmbeddingModel must not be null");
this.elasticsearchClient = new ElasticsearchClient(new RestClientTransport(restClient, new JacksonJsonpMapper(
@@ -220,6 +223,11 @@ public class ElasticsearchVectorStore implements VectorStore, InitializingBean {
@Override
public void afterPropertiesSet() {
if (!this.initializeSchema) {
return;
}
if (!indexExists()) {
createIndexMapping();
}

View File

@@ -363,7 +363,7 @@ class ElasticsearchVectorStoreIT {
public ElasticsearchVectorStore vectorStore(EmbeddingModel embeddingModel) {
return new ElasticsearchVectorStore(
RestClient.builder(HttpHost.create(elasticsearchContainer.getHttpHostAddress())).build(),
embeddingModel);
embeddingModel, true);
}
@Bean

View File

@@ -1,6 +1,8 @@
spring.ai.openai.api-key=${OPENAI_API_KEY}
spring.ai.openai.embedding.options.model=text-embedding-ada-002
spring.datasource.driver-class-name=com.sap.db.jdbc.Driver
spring.datasource.url=${HANA_DATASOURCE_URL}
spring.datasource.username=${HANA_DATASOURCE_USERNAME}

View File

@@ -96,6 +96,8 @@ public class MilvusVectorStore implements VectorStore, InitializingBean {
private final MilvusVectorStoreConfig config;
private final boolean initializeSchema;
/**
* Configuration for the Milvus vector store.
*/
@@ -242,12 +244,14 @@ public class MilvusVectorStore implements VectorStore, InitializingBean {
}
public MilvusVectorStore(MilvusServiceClient milvusClient, EmbeddingModel embeddingModel) {
this(milvusClient, embeddingModel, MilvusVectorStoreConfig.defaultConfig());
public MilvusVectorStore(MilvusServiceClient milvusClient, EmbeddingModel embeddingModel,
boolean initializeSchema) {
this(milvusClient, embeddingModel, MilvusVectorStoreConfig.defaultConfig(), initializeSchema);
}
public MilvusVectorStore(MilvusServiceClient milvusClient, EmbeddingModel embeddingModel,
MilvusVectorStoreConfig config) {
MilvusVectorStoreConfig config, boolean initializeSchema) {
this.initializeSchema = initializeSchema;
Assert.notNull(milvusClient, "MilvusServiceClient must not be null");
Assert.notNull(milvusClient, "EmbeddingModel must not be null");
@@ -380,6 +384,11 @@ public class MilvusVectorStore implements VectorStore, InitializingBean {
// ---------------------------------------------------------------------------------
@Override
public void afterPropertiesSet() throws Exception {
if (!this.initializeSchema) {
return;
}
this.createCollection();
}

View File

@@ -51,7 +51,7 @@ public class MilvusEmbeddingDimensionsTests {
.withEmbeddingDimension(explicitDimensions)
.build();
var dim = new MilvusVectorStore(milvusClient, embeddingModel, config).embeddingDimensions();
var dim = new MilvusVectorStore(milvusClient, embeddingModel, config, true).embeddingDimensions();
assertThat(dim).isEqualTo(explicitDimensions);
verify(embeddingModel, never()).dimensions();
@@ -63,7 +63,8 @@ public class MilvusEmbeddingDimensionsTests {
MilvusVectorStoreConfig config = MilvusVectorStoreConfig.builder().build();
var dim = new MilvusVectorStore(milvusClient, embeddingModel, config).embeddingDimensions();
var dim = new MilvusVectorStore(milvusClient, embeddingModel, config ,true)
.embeddingDimensions();
assertThat(dim).isEqualTo(969);
@@ -76,7 +77,7 @@ public class MilvusEmbeddingDimensionsTests {
when(embeddingModel.dimensions()).thenThrow(new RuntimeException());
var dim = new MilvusVectorStore(milvusClient, embeddingModel,
MilvusVectorStoreConfig.builder().build())
MilvusVectorStoreConfig.builder().build() ,true)
.embeddingDimensions();
assertThat(dim).isEqualTo(MilvusVectorStore.OPENAI_EMBEDDING_DIMENSION_SIZE);

View File

@@ -265,7 +265,7 @@ public class MilvusVectorStoreIT {
.withIndexType(IndexType.IVF_FLAT)
.withMetricType(metricType)
.build();
return new MilvusVectorStore(milvusClient, embeddingModel, config);
return new MilvusVectorStore(milvusClient, embeddingModel, config, true);
}
@Bean

View File

@@ -64,20 +64,28 @@ public class MongoDBAtlasVectorStore implements VectorStore, InitializingBean {
private final MongoDBAtlasFilterExpressionConverter filterExpressionConverter = new MongoDBAtlasFilterExpressionConverter();
public MongoDBAtlasVectorStore(MongoTemplate mongoTemplate, EmbeddingModel embeddingModel) {
this(mongoTemplate, embeddingModel, MongoDBVectorStoreConfig.defaultConfig());
private final boolean initializeSchema;
public MongoDBAtlasVectorStore(MongoTemplate mongoTemplate, EmbeddingModel embeddingModel,
boolean initializeSchema) {
this(mongoTemplate, embeddingModel, MongoDBVectorStoreConfig.defaultConfig(), initializeSchema);
}
public MongoDBAtlasVectorStore(MongoTemplate mongoTemplate, EmbeddingModel embeddingModel,
MongoDBVectorStoreConfig config) {
MongoDBVectorStoreConfig config, boolean initializeSchema) {
this.mongoTemplate = mongoTemplate;
this.embeddingModel = embeddingModel;
this.config = config;
this.initializeSchema = initializeSchema;
}
@Override
public void afterPropertiesSet() throws Exception {
if (!this.initializeSchema) {
return;
}
// Create the collection if it does not exist
if (!mongoTemplate.collectionExists(this.config.collectionName)) {
mongoTemplate.createCollection(this.config.collectionName);

View File

@@ -196,7 +196,8 @@ class MongoDBAtlasVectorStoreIT {
return new MongoDBAtlasVectorStore(mongoTemplate, embeddingModel,
MongoDBAtlasVectorStore.MongoDBVectorStoreConfig.builder()
.withMetadataFieldsToFilter(List.of("country", "year"))
.build());
.build(),
true);
}
@Bean

View File

@@ -273,7 +273,11 @@ public class Neo4jVectorStore implements VectorStore, InitializingBean {
private final Neo4jVectorStoreConfig config;
public Neo4jVectorStore(Driver driver, EmbeddingModel embeddingModel, Neo4jVectorStoreConfig config) {
private final boolean initializeSchema;
public Neo4jVectorStore(Driver driver, EmbeddingModel embeddingModel, Neo4jVectorStoreConfig config,
boolean initializeSchema) {
this.initializeSchema = initializeSchema;
Assert.notNull(driver, "Neo4j driver must not be null");
Assert.notNull(embeddingModel, "Embedding client must not be null");
@@ -351,6 +355,10 @@ public class Neo4jVectorStore implements VectorStore, InitializingBean {
@Override
public void afterPropertiesSet() {
if (!this.initializeSchema) {
return;
}
try (var session = this.driver.session(this.config.sessionConfig)) {
session

View File

@@ -295,8 +295,8 @@ class Neo4jVectorStoreIT {
@Bean
public VectorStore vectorStore(Driver driver, EmbeddingModel embeddingModel) {
return new Neo4jVectorStore(driver, embeddingModel,
Neo4jVectorStore.Neo4jVectorStoreConfig.defaultConfig());
return new Neo4jVectorStore(driver, embeddingModel, Neo4jVectorStore.Neo4jVectorStoreConfig.defaultConfig(),
true);
}
@Bean

View File

@@ -49,6 +49,7 @@ import org.springframework.util.StringUtils;
* vector index will be auto-created if not available.
*
* @author Christian Tzolov
* @author Josh Long
*/
public class PgVectorStore implements VectorStore, InitializingBean {
@@ -78,6 +79,8 @@ public class PgVectorStore implements VectorStore, InitializingBean {
private PgIndexType createIndexMethod;
private final boolean initializeSchema;
/**
* By default, pgvector performs exact nearest neighbor search, which provides perfect
* recall. You can add an index to use approximate nearest neighbor search, which
@@ -199,16 +202,17 @@ public class PgVectorStore implements VectorStore, InitializingBean {
public PgVectorStore(JdbcTemplate jdbcTemplate, EmbeddingModel embeddingModel) {
this(jdbcTemplate, embeddingModel, INVALID_EMBEDDING_DIMENSION, PgVectorStore.PgDistanceType.COSINE_DISTANCE,
false, PgIndexType.NONE);
false, PgIndexType.NONE, false);
}
public PgVectorStore(JdbcTemplate jdbcTemplate, EmbeddingModel embeddingModel, int dimensions) {
this(jdbcTemplate, embeddingModel, dimensions, PgVectorStore.PgDistanceType.COSINE_DISTANCE, false,
PgIndexType.NONE);
PgIndexType.NONE, false);
}
public PgVectorStore(JdbcTemplate jdbcTemplate, EmbeddingModel embeddingModel, int dimensions,
PgDistanceType distanceType, boolean removeExistingVectorStoreTable, PgIndexType createIndexMethod) {
PgDistanceType distanceType, boolean removeExistingVectorStoreTable, PgIndexType createIndexMethod,
boolean initializeSchema) {
this.jdbcTemplate = jdbcTemplate;
this.embeddingModel = embeddingModel;
@@ -216,6 +220,7 @@ public class PgVectorStore implements VectorStore, InitializingBean {
this.distanceType = distanceType;
this.removeExistingVectorStoreTable = removeExistingVectorStoreTable;
this.createIndexMethod = createIndexMethod;
this.initializeSchema = initializeSchema;
}
public PgDistanceType getDistanceType() {
@@ -333,6 +338,11 @@ public class PgVectorStore implements VectorStore, InitializingBean {
// ---------------------------------------------------------------------------------
@Override
public void afterPropertiesSet() throws Exception {
if (!this.initializeSchema) {
return;
}
// Enable the PGVector, JSONB and UUID support.
this.jdbcTemplate.execute("CREATE EXTENSION IF NOT EXISTS vector");
this.jdbcTemplate.execute("CREATE EXTENSION IF NOT EXISTS hstore");

View File

@@ -308,7 +308,7 @@ public class PgVectorStoreIT {
@Bean
public VectorStore vectorStore(JdbcTemplate jdbcTemplate, EmbeddingModel embeddingModel) {
return new PgVectorStore(jdbcTemplate, embeddingModel, PgVectorStore.INVALID_EMBEDDING_DIMENSION,
distanceType, true, PgIndexType.HNSW);
distanceType, true, PgIndexType.HNSW, true);
}
@Bean

View File

@@ -15,24 +15,12 @@
*/
package org.springframework.ai.vectorstore.qdrant;
import static io.qdrant.client.PointIdFactory.id;
import static io.qdrant.client.ValueFactory.value;
import static io.qdrant.client.VectorsFactory.vectors;
import static io.qdrant.client.WithPayloadSelectorFactory.enable;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.ExecutionException;
import org.springframework.ai.document.Document;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.vectorstore.SearchRequest;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;
import io.qdrant.client.QdrantClient;
import io.qdrant.client.grpc.Collections.Distance;
import io.qdrant.client.grpc.Collections.VectorParams;
@@ -43,6 +31,17 @@ import io.qdrant.client.grpc.Points.PointStruct;
import io.qdrant.client.grpc.Points.ScoredPoint;
import io.qdrant.client.grpc.Points.SearchPoints;
import io.qdrant.client.grpc.Points.UpdateStatus;
import org.springframework.ai.document.Document;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.vectorstore.SearchRequest;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;
import static io.qdrant.client.PointIdFactory.id;
import static io.qdrant.client.ValueFactory.value;
import static io.qdrant.client.VectorsFactory.vectors;
import static io.qdrant.client.WithPayloadSelectorFactory.enable;
/**
* Qdrant vectorStore implementation. This store supports creating, updating, deleting,
@@ -51,6 +50,7 @@ import io.qdrant.client.grpc.Points.UpdateStatus;
* @author Anush Shetty
* @author Christian Tzolov
* @author Eddú Meléndez
* @author Josh Long
* @since 0.8.1
*/
public class QdrantVectorStore implements VectorStore, InitializingBean {
@@ -69,6 +69,8 @@ public class QdrantVectorStore implements VectorStore, InitializingBean {
private final QdrantFilterExpressionConverter filterExpressionConverter = new QdrantFilterExpressionConverter();
private final boolean initializeSchema;
/**
* Configuration class for the QdrantVectorStore.
*
@@ -84,6 +86,7 @@ public class QdrantVectorStore implements VectorStore, InitializingBean {
*
* @param builder The configuration builder.
*/
private QdrantVectorStoreConfig(Builder builder) {
this.collectionName = builder.collectionName;
}
@@ -137,8 +140,9 @@ public class QdrantVectorStore implements VectorStore, InitializingBean {
* @deprecated since 1.0.0 in favor of {@link QdrantVectorStore}.
*/
@Deprecated(since = "1.0.0", forRemoval = true)
public QdrantVectorStore(QdrantClient qdrantClient, QdrantVectorStoreConfig config, EmbeddingModel embeddingModel) {
this(qdrantClient, config.collectionName, embeddingModel);
public QdrantVectorStore(QdrantClient qdrantClient, QdrantVectorStoreConfig config, EmbeddingModel embeddingModel,
boolean initializeSchema) {
this(qdrantClient, config.collectionName, embeddingModel, initializeSchema);
}
/**
@@ -147,11 +151,13 @@ public class QdrantVectorStore implements VectorStore, InitializingBean {
* @param collectionName The name of the collection to use in Qdrant.
* @param embeddingModel The client for embedding operations.
*/
public QdrantVectorStore(QdrantClient qdrantClient, String collectionName, EmbeddingModel embeddingModel) {
public QdrantVectorStore(QdrantClient qdrantClient, String collectionName, EmbeddingModel embeddingModel,
boolean initializeSchema) {
Assert.notNull(qdrantClient, "QdrantClient must not be null");
Assert.notNull(collectionName, "collectionName must not be null");
Assert.notNull(embeddingModel, "EmbeddingModel must not be null");
this.initializeSchema = initializeSchema;
this.embeddingModel = embeddingModel;
this.collectionName = collectionName;
this.qdrantClient = qdrantClient;
@@ -285,6 +291,10 @@ public class QdrantVectorStore implements VectorStore, InitializingBean {
@Override
public void afterPropertiesSet() throws Exception {
if (!this.initializeSchema)
return;
// Create the collection if it does not exist.
if (!isCollectionExists()) {
var vectorParams = VectorParams.newBuilder()

View File

@@ -48,6 +48,7 @@ import static org.assertj.core.api.Assertions.assertThat;
/**
* @author Anush Shetty
* @author Josh Long
* @since 0.8.1
*/
@Testcontainers
@@ -251,7 +252,7 @@ public class QdrantVectorStoreIT {
@Bean
public VectorStore qdrantVectorStore(EmbeddingModel embeddingModel, QdrantClient qdrantClient) {
return new QdrantVectorStore(qdrantClient, COLLECTION_NAME, embeddingModel);
return new QdrantVectorStore(qdrantClient, COLLECTION_NAME, embeddingModel, true);
}
@Bean

View File

@@ -34,7 +34,6 @@ import org.springframework.ai.vectorstore.filter.FilterExpressionConverter;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import redis.clients.jedis.JedisPooled;
import redis.clients.jedis.Pipeline;
import redis.clients.jedis.json.Path2;
@@ -246,6 +245,8 @@ public class RedisVectorStore implements VectorStore, InitializingBean {
}
private final boolean initializeSchema;
public static final String DEFAULT_URI = "redis://localhost:6379";
public static final String DEFAULT_INDEX_NAME = "spring-ai-index";
@@ -286,10 +287,11 @@ public class RedisVectorStore implements VectorStore, InitializingBean {
private FilterExpressionConverter filterExpressionConverter;
public RedisVectorStore(RedisVectorStoreConfig config, EmbeddingModel embeddingModel) {
public RedisVectorStore(RedisVectorStoreConfig config, EmbeddingModel embeddingModel, boolean initializeSchema) {
Assert.notNull(config, "Config must not be null");
Assert.notNull(embeddingModel, "Embedding client must not be null");
this.initializeSchema = initializeSchema;
this.jedis = new JedisPooled(config.uri);
this.embeddingModel = embeddingModel;
@@ -405,6 +407,10 @@ public class RedisVectorStore implements VectorStore, InitializingBean {
@Override
public void afterPropertiesSet() {
if (!this.initializeSchema) {
return;
}
// If index already exists don't do anything
if (this.jedis.ftList().contains(this.config.indexName)) {
return;

View File

@@ -250,7 +250,7 @@ class RedisVectorStoreIT {
.withURI(redisContainer.getRedisURI())
.withMetadataFields(MetadataField.tag("meta1"), MetadataField.tag("meta2"),
MetadataField.tag("country"), MetadataField.numeric("year"))
.build(), embeddingModel);
.build(), embeddingModel, true);
}
@Bean

View File

@@ -61,6 +61,7 @@ import org.springframework.util.StringUtils;
*
* @author Christian Tzolov
* @author Eddú Meléndez
* @author Josh Long
*/
public class WeaviateVectorStore implements VectorStore, InitializingBean {
@@ -280,10 +281,11 @@ public class WeaviateVectorStore implements VectorStore, InitializingBean {
* @param embeddingModel The client for embedding operations.
*/
public WeaviateVectorStore(WeaviateVectorStoreConfig vectorStoreConfig, EmbeddingModel embeddingModel,
WeaviateClient weaviateClient) {
WeaviateClient weaviateClient, boolean initializeSchema) {
Assert.notNull(vectorStoreConfig, "WeaviateVectorStoreConfig must not be null");
Assert.notNull(embeddingModel, "EmbeddingModel must not be null");
this.initializeSchema = initializeSchema;
this.embeddingModel = embeddingModel;
this.consistencyLevel = vectorStoreConfig.consistencyLevel;
this.weaviateObjectClass = vectorStoreConfig.weaviateObjectClass;
@@ -524,9 +526,15 @@ public class WeaviateVectorStore implements VectorStore, InitializingBean {
return doubleList.stream().map(Number::floatValue).toList().toArray(new Float[0]);
}
private final boolean initializeSchema;
@Override
public void afterPropertiesSet() throws Exception {
if (!this.initializeSchema) {
return;
}
Map<String, Object> metadata = new HashMap<>();
if (!CollectionUtils.isEmpty(this.filterMetadataFields)) {
for (MetadataField mf : this.filterMetadataFields) {

View File

@@ -25,9 +25,6 @@ import java.util.UUID;
import io.weaviate.client.Config;
import io.weaviate.client.WeaviateClient;
import org.junit.jupiter.api.Test;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import org.springframework.ai.document.Document;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.transformers.TransformersEmbeddingModel;
@@ -38,8 +35,17 @@ import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.core.io.DefaultResourceLoader;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import org.testcontainers.weaviate.WeaviateContainer;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import static org.assertj.core.api.Assertions.assertThat;
/**
@@ -252,9 +258,8 @@ public class WeaviateVectorStoreIT {
.withConsistencyLevel(WeaviateVectorStoreConfig.ConsistentLevel.ONE)
.build();
WeaviateVectorStore vectorStore = new WeaviateVectorStore(config, embeddingModel, weaviateClient);
return new WeaviateVectorStore(config, embeddingModel, weaviateClient, true);
return vectorStore;
}
@Bean