Unify the vector store module and pom names

spring-ai-qdrant -> spring-ai-qdrant-store
 spring-ai-cassandra -> spring-ai-cassandra-store
 spring-ai-pinecone -> spring-ai-pinecone-store
 spring-ai-redis -> spring-ai-redis-store
 spring-ai-qdrant -> spring-ai-qdrant-store
 spring-ai-gemfire -> spring-ai-gemfire-store
 spring-ai-azure-vector-store-spring-boot-starter -> spring-ai-azure-store-spring-boot-starter
 spring-ai-redis-spring-boot-starter -> spring-ai-redis-store-spring-boot-starter
This commit is contained in:
Christian Tzolov
2024-05-17 17:05:03 +02:00
parent 1985824fa9
commit 3475f17e98
61 changed files with 273 additions and 302 deletions

View File

@@ -77,7 +77,7 @@
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-qdrant</artifactId>
<artifactId>spring-ai-qdrant-store</artifactId>
<version>${project.version}</version>
<exclusions>
<exclusion>

106
pom.xml
View File

@@ -13,67 +13,73 @@
<description>Building AI applications with Spring Boot</description>
<modules>
<module>spring-ai-docs</module>
<module>spring-ai-bom</module>
<module>spring-ai-core</module>
<module>models/spring-ai-transformers</module>
<module>models/spring-ai-postgresml</module>
<module>models/spring-ai-bedrock</module>
<module>models/spring-ai-azure-openai</module>
<module>models/spring-ai-huggingface</module>
<module>models/spring-ai-ollama</module>
<module>models/spring-ai-openai</module>
<module>models/spring-ai-stability-ai</module>
<module>models/spring-ai-mistral-ai</module>
<module>models/spring-ai-vertex-ai-palm2</module>
<module>models/spring-ai-vertex-ai-gemini</module>
<module>models/spring-ai-anthropic</module>
<module>models/spring-ai-watsonx-ai</module>
<module>spring-ai-test</module>
<module>spring-ai-spring-boot-autoconfigure</module>
<module>spring-ai-spring-boot-starters/spring-ai-starter-openai</module>
<module>spring-ai-spring-boot-starters/spring-ai-starter-azure-openai</module>
<module>spring-ai-spring-boot-starters/spring-ai-starter-ollama</module>
<module>spring-ai-spring-boot-starters/spring-ai-starter-transformers</module>
<module>spring-ai-spring-boot-starters/spring-ai-starter-cassandra</module>
<module>spring-ai-spring-boot-starters/spring-ai-starter-chroma-store</module>
<module>spring-ai-spring-boot-starters/spring-ai-starter-milvus-store</module>
<module>spring-ai-spring-boot-starters/spring-ai-starter-pgvector-store</module>
<module>spring-ai-spring-boot-starters/spring-ai-starter-hanadb-store</module>
<module>spring-ai-spring-boot-starters/spring-ai-starter-pinecone-store</module>
<module>spring-ai-spring-boot-starters/spring-ai-starter-azure-store</module>
<module>spring-ai-spring-boot-starters/spring-ai-starter-weaviate-store</module>
<module>spring-ai-spring-boot-starters/spring-ai-starter-redis</module>
<module>spring-ai-spring-boot-starters/spring-ai-starter-stability-ai</module>
<module>spring-ai-spring-boot-starters/spring-ai-starter-neo4j-store</module>
<module>spring-ai-spring-boot-starters/spring-ai-starter-qdrant-store</module>
<module>spring-ai-spring-boot-starters/spring-ai-starter-postgresml-embedding</module>
<module>spring-ai-docs</module>
<module>vector-stores/spring-ai-cassandra</module>
<module>vector-stores/spring-ai-pgvector-store</module>
<module>vector-stores/spring-ai-hanadb-store</module>
<module>vector-stores/spring-ai-milvus-store</module>
<module>vector-stores/spring-ai-neo4j-store</module>
<module>spring-ai-retry</module>
<module>spring-ai-spring-boot-testcontainers</module>
<module>document-readers/pdf-reader</module>
<module>document-readers/tika-reader</module>
<module>vector-stores/spring-ai-pinecone</module>
<module>vector-stores/spring-ai-chroma-store</module>
<module>vector-stores/spring-ai-azure-store</module>
<module>vector-stores/spring-ai-cassandra-store</module>
<module>vector-stores/spring-ai-chroma-store</module>
<module>vector-stores/spring-ai-elasticsearch-store</module>
<module>vector-stores/spring-ai-gemfire-store</module>
<module>vector-stores/spring-ai-hanadb-store</module>
<module>vector-stores/spring-ai-milvus-store</module>
<module>vector-stores/spring-ai-mongodb-atlas-store</module>
<module>vector-stores/spring-ai-neo4j-store</module>
<module>vector-stores/spring-ai-pgvector-store</module>
<module>vector-stores/spring-ai-pinecone-store</module>
<module>vector-stores/spring-ai-qdrant-store</module>
<module>vector-stores/spring-ai-redis-store</module>
<module>vector-stores/spring-ai-weaviate-store</module>
<module>vector-stores/spring-ai-redis</module>
<module>vector-stores/spring-ai-gemfire</module>
<module>spring-ai-spring-boot-starters/spring-ai-starter-vertex-ai-palm2</module>
<module>spring-ai-spring-boot-starters/spring-ai-starter-vertex-ai-gemini</module>
<module>vector-stores/spring-ai-qdrant</module>
<module>spring-ai-spring-boot-starters/spring-ai-starter-azure-store</module>
<module>spring-ai-spring-boot-starters/spring-ai-starter-cassandra-store</module>
<module>spring-ai-spring-boot-starters/spring-ai-starter-chroma-store</module>
<module>spring-ai-spring-boot-starters/spring-ai-starter-elasticsearch-store</module>
<module>spring-ai-spring-boot-starters/spring-ai-starter-hanadb-store</module>
<module>spring-ai-spring-boot-starters/spring-ai-starter-milvus-store</module>
<module>spring-ai-spring-boot-starters/spring-ai-starter-mongodb-atlas-store</module>
<module>spring-ai-spring-boot-starters/spring-ai-starter-neo4j-store</module>
<module>spring-ai-spring-boot-starters/spring-ai-starter-pgvector-store</module>
<module>spring-ai-spring-boot-starters/spring-ai-starter-pinecone-store</module>
<module>spring-ai-spring-boot-starters/spring-ai-starter-qdrant-store</module>
<module>spring-ai-spring-boot-starters/spring-ai-starter-redis-store</module>
<module>spring-ai-spring-boot-starters/spring-ai-starter-weaviate-store</module>
<module>models/spring-ai-anthropic</module>
<module>models/spring-ai-azure-openai</module>
<module>models/spring-ai-bedrock</module>
<module>models/spring-ai-huggingface</module>
<module>models/spring-ai-mistral-ai</module>
<module>models/spring-ai-ollama</module>
<module>models/spring-ai-openai</module>
<module>models/spring-ai-postgresml</module>
<module>models/spring-ai-stability-ai</module>
<module>models/spring-ai-transformers</module>
<module>models/spring-ai-vertex-ai-gemini</module>
<module>models/spring-ai-vertex-ai-palm2</module>
<module>models/spring-ai-watsonx-ai</module>
<module>spring-ai-spring-boot-starters/spring-ai-starter-anthropic</module>
<module>spring-ai-spring-boot-starters/spring-ai-starter-azure-openai</module>
<module>spring-ai-spring-boot-starters/spring-ai-starter-bedrock-ai</module>
<module>spring-ai-spring-boot-starters/spring-ai-starter-mistral-ai</module>
<module>spring-ai-retry</module>
<module>vector-stores/spring-ai-mongodb-atlas-store</module>
<module>spring-ai-spring-boot-starters/spring-ai-starter-mongodb-atlas-store</module>
<module>spring-ai-spring-boot-testcontainers</module>
<module>spring-ai-spring-boot-starters/spring-ai-starter-anthropic</module>
<module>vector-stores/spring-ai-elasticsearch-store</module>
<module>spring-ai-spring-boot-starters/spring-ai-starter-ollama</module>
<module>spring-ai-spring-boot-starters/spring-ai-starter-openai</module>
<module>spring-ai-spring-boot-starters/spring-ai-starter-postgresml-embedding</module>
<module>spring-ai-spring-boot-starters/spring-ai-starter-stability-ai</module>
<module>spring-ai-spring-boot-starters/spring-ai-starter-transformers</module>
<module>spring-ai-spring-boot-starters/spring-ai-starter-vertex-ai-gemini</module>
<module>spring-ai-spring-boot-starters/spring-ai-starter-vertex-ai-palm2</module>
<module>spring-ai-spring-boot-starters/spring-ai-starter-watsonx-ai</module>
<module>spring-ai-spring-boot-starters/spring-ai-starter-elasticsearch-store</module>
</modules>
<organization>

View File

@@ -134,7 +134,7 @@
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-cassandra</artifactId>
<artifactId>spring-ai-cassandra-store</artifactId>
<version>${project.version}</version>
</dependency>
@@ -170,13 +170,13 @@
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-pinecone</artifactId>
<artifactId>spring-ai-pinecone-store</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-redis</artifactId>
<artifactId>spring-ai-redis-store</artifactId>
<version>${project.version}</version>
</dependency>
@@ -188,7 +188,7 @@
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-qdrant</artifactId>
<artifactId>spring-ai-qdrant-store</artifactId>
<version>${project.version}</version>
</dependency>
@@ -206,7 +206,7 @@
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-gemfire</artifactId>
<artifactId>spring-ai-gemfire-store</artifactId>
<version>${project.version}</version>
</dependency>
@@ -238,7 +238,7 @@
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-azure-vector-store-spring-boot-starter</artifactId>
<artifactId>spring-ai-azure-store-spring-boot-starter</artifactId>
<version>${project.version}</version>
</dependency>
@@ -316,7 +316,7 @@
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-redis-spring-boot-starter</artifactId>
<artifactId>spring-ai-redis-store-spring-boot-starter</artifactId>
<version>${project.version}</version>
</dependency>

View File

@@ -57,7 +57,7 @@ Add these dependencies to your project:
----
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-cassandra</artifactId>
<artifactId>spring-ai-cassandra-store</artifactId>
</dependency>
----
@@ -67,7 +67,7 @@ Add these dependencies to your project:
----
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-cassandra-spring-boot-starter</artifactId>
<artifactId>spring-ai-cassandra-store-spring-boot-starter</artifactId>
</dependency>
----

View File

@@ -37,7 +37,7 @@ Add these dependencies to your project:
----
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-gemfire</artifactId>
<artifactId>spring-ai-gemfire-store</artifactId>
</dependency>
----

View File

@@ -172,7 +172,7 @@ Add these dependencies to your project:
----
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-pinecone</artifactId>
<artifactId>spring-ai-pinecone-store</artifactId>
</dependency>
----

View File

@@ -147,13 +147,13 @@ NOTE: These filter expressions are converted into the equivalent Qdrant link:htt
== Manual Configuration
Instead of using the Spring Boot auto-configuration, you can manually configure the `QdrantVectorStore`. For this you need to add the `spring-ai-qdrant` dependency to your project:
Instead of using the Spring Boot auto-configuration, you can manually configure the `QdrantVectorStore`. For this you need to add the `spring-ai-qdrant-store` dependency to your project:
[source,xml]
----
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-qdrant</artifactId>
<artifactId>spring-ai-qdrant-store</artifactId>
</dependency>
----

View File

@@ -162,7 +162,7 @@ Add the Redis Vector Store and Jedis dependencies
----
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-redis</artifactId>
<artifactId>spring-ai-redis-store</artifactId>
</dependency>
<dependency>

View File

@@ -80,7 +80,7 @@
<!-- Pinecone Vector Store-->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-pinecone</artifactId>
<artifactId>spring-ai-pinecone-store</artifactId>
<version>${project.parent.version}</version>
<optional>true</optional>
</dependency>
@@ -149,7 +149,7 @@
<!-- Apache Cassandra Vector Store -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-cassandra</artifactId>
<artifactId>spring-ai-cassandra-store</artifactId>
<version>${project.parent.version}</version>
<optional>true</optional>
</dependency>
@@ -165,7 +165,7 @@
<!-- Redis Vector Store-->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-redis</artifactId>
<artifactId>spring-ai-redis-store</artifactId>
<version>${project.parent.version}</version>
<optional>true</optional>
</dependency>
@@ -242,7 +242,7 @@
<!-- Qdrant Vector Store-->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-qdrant</artifactId>
<artifactId>spring-ai-qdrant-store</artifactId>
<version>${project.parent.version}</version>
<optional>true</optional>
</dependency>

View File

@@ -7,7 +7,7 @@
<version>1.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<artifactId>spring-ai-azure-vector-store-spring-boot-starter</artifactId>
<artifactId>spring-ai-azure-store-spring-boot-starter</artifactId>
<packaging>jar</packaging>
<name>Spring AI Starter - Azure Vector Store</name>
<description>Spring AI Azure Vector Store Auto Configuration</description>

View File

@@ -7,7 +7,7 @@
<version>1.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<artifactId>spring-ai-cassandra-spring-boot-starter</artifactId>
<artifactId>spring-ai-cassandra-store-spring-boot-starter</artifactId>
<packaging>jar</packaging>
<name>Spring AI Starter - Apache Cassandra Vector Store</name>
<description>Spring AI Apache Cassandra Vector Store Auto Configuration</description>
@@ -34,7 +34,7 @@
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-cassandra</artifactId>
<artifactId>spring-ai-cassandra-store</artifactId>
<version>${project.parent.version}</version>
</dependency>
</dependencies>

View File

@@ -34,7 +34,7 @@
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-pinecone</artifactId>
<artifactId>spring-ai-pinecone-store</artifactId>
<version>${project.parent.version}</version>
</dependency>
</dependencies>

View File

@@ -34,7 +34,7 @@
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-qdrant</artifactId>
<artifactId>spring-ai-qdrant-store</artifactId>
<version>${project.parent.version}</version>
</dependency>
</dependencies>

View File

@@ -7,7 +7,7 @@
<version>1.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<artifactId>spring-ai-redis-spring-boot-starter</artifactId>
<artifactId>spring-ai-redis-store-spring-boot-starter</artifactId>
<packaging>jar</packaging>
<name>Spring AI Starter - Redis Vector Store</name>
<description>Spring AI Redis Vector Store Auto Configuration</description>
@@ -34,7 +34,7 @@
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-redis</artifactId>
<artifactId>spring-ai-redis-store</artifactId>
<version>${project.parent.version}</version>
</dependency>
</dependencies>

View File

@@ -94,7 +94,7 @@
<!-- Redis Vector Store-->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-redis</artifactId>
<artifactId>spring-ai-redis-store</artifactId>
<version>${project.parent.version}</version>
<optional>true</optional>
</dependency>
@@ -110,7 +110,7 @@
<!-- Qdrant Vector Store-->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-qdrant</artifactId>
<artifactId>spring-ai-qdrant-store</artifactId>
<version>${project.parent.version}</version>
<optional>true</optional>
</dependency>

View File

@@ -49,9 +49,7 @@ import org.springframework.ai.embedding.EmbeddingClient;
import org.springframework.ai.vectorstore.SearchRequest;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.ai.vectorstore.filter.FilterExpressionConverter;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.lang.NonNull;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
@@ -65,9 +63,8 @@ import org.springframework.util.StringUtils;
* @author Greg Meyer
* @author Xiangyang Yu
* @author Christian Tzolov
* @author Josh Long
*/
public class AzureVectorStore implements VectorStore, ApplicationListener<ApplicationReadyEvent> {
public class AzureVectorStore implements VectorStore, InitializingBean {
private static final Logger logger = LoggerFactory.getLogger(AzureVectorStore.class);
@@ -118,53 +115,6 @@ public class AzureVectorStore implements VectorStore, ApplicationListener<Applic
*/
private final List<MetadataField> filterMetadataFields;
@Override
public void onApplicationEvent(@NonNull ApplicationReadyEvent event) {
int dimensions = this.embeddingClient.dimensions();
List<SearchField> fields = new ArrayList<>();
fields.add(new SearchField(ID_FIELD_NAME, SearchFieldDataType.STRING).setKey(true)
.setFilterable(true)
.setSortable(true));
fields.add(new SearchField(EMBEDDING_FIELD_NAME, SearchFieldDataType.collection(SearchFieldDataType.SINGLE))
.setSearchable(true)
.setVectorSearchDimensions(dimensions)
// This must match a vector search configuration name.
.setVectorSearchProfileName(SPRING_AI_VECTOR_PROFILE));
fields.add(new SearchField(CONTENT_FIELD_NAME, SearchFieldDataType.STRING).setSearchable(true)
.setFilterable(true));
fields.add(new SearchField(METADATA_FIELD_NAME, SearchFieldDataType.STRING).setSearchable(true)
.setFilterable(true));
for (MetadataField filterableMetadataField : this.filterMetadataFields) {
fields.add(new SearchField(METADATA_FIELD_PREFIX + filterableMetadataField.name(),
filterableMetadataField.fieldType())
.setSearchable(false)
.setFacetable(true));
}
SearchIndex searchIndex = new SearchIndex(this.indexName).setFields(fields)
// VectorSearch configuration is required for a vector field. The name used
// for the vector search algorithm configuration must match the configuration
// used by the search field used for vector search.
.setVectorSearch(new VectorSearch()
.setProfiles(Collections
.singletonList(new VectorSearchProfile(SPRING_AI_VECTOR_PROFILE, SPRING_AI_VECTOR_CONFIG)))
.setAlgorithms(Collections.singletonList(new HnswAlgorithmConfiguration(SPRING_AI_VECTOR_CONFIG)
.setParameters(new HnswParameters().setM(4)
.setEfConstruction(400)
.setEfSearch(1000)
.setMetric(VectorSearchAlgorithmMetric.COSINE)))));
SearchIndex index = this.searchIndexClient.createOrUpdateIndex(searchIndex);
logger.info("Created search index: " + index.getName());
this.searchClient = this.searchIndexClient.getSearchClient(this.indexName);
}
public record MetadataField(String name, SearchFieldDataType fieldType) {
public static MetadataField text(String name) {
@@ -375,4 +325,51 @@ public class AzureVectorStore implements VectorStore, ApplicationListener<Applic
private record AzureSearchDocument(String id, String content, List<Double> embedding, String metadata) {
}
}
@Override
public void afterPropertiesSet() throws Exception {
int dimensions = this.embeddingClient.dimensions();
List<SearchField> fields = new ArrayList<>();
fields.add(new SearchField(ID_FIELD_NAME, SearchFieldDataType.STRING).setKey(true)
.setFilterable(true)
.setSortable(true));
fields.add(new SearchField(EMBEDDING_FIELD_NAME, SearchFieldDataType.collection(SearchFieldDataType.SINGLE))
.setSearchable(true)
.setVectorSearchDimensions(dimensions)
// This must match a vector search configuration name.
.setVectorSearchProfileName(SPRING_AI_VECTOR_PROFILE));
fields.add(new SearchField(CONTENT_FIELD_NAME, SearchFieldDataType.STRING).setSearchable(true)
.setFilterable(true));
fields.add(new SearchField(METADATA_FIELD_NAME, SearchFieldDataType.STRING).setSearchable(true)
.setFilterable(true));
for (MetadataField filterableMetadataField : this.filterMetadataFields) {
fields.add(new SearchField(METADATA_FIELD_PREFIX + filterableMetadataField.name(),
filterableMetadataField.fieldType())
.setSearchable(false)
.setFacetable(true));
}
SearchIndex searchIndex = new SearchIndex(this.indexName).setFields(fields)
// VectorSearch configuration is required for a vector field. The name used
// for the vector search algorithm configuration must match the configuration
// used by the search field used for vector search.
.setVectorSearch(new VectorSearch()
.setProfiles(Collections
.singletonList(new VectorSearchProfile(SPRING_AI_VECTOR_PROFILE, SPRING_AI_VECTOR_CONFIG)))
.setAlgorithms(Collections.singletonList(new HnswAlgorithmConfiguration(SPRING_AI_VECTOR_CONFIG)
.setParameters(new HnswParameters().setM(4)
.setEfConstruction(400)
.setEfSearch(1000)
.setMetric(VectorSearchAlgorithmMetric.COSINE)))));
SearchIndex index = this.searchIndexClient.createOrUpdateIndex(searchIndex);
logger.info("Created search index: " + index.getName());
this.searchClient = this.searchIndexClient.getSearchClient(this.indexName);
}
}

View File

@@ -8,7 +8,7 @@
<version>1.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<artifactId>spring-ai-cassandra</artifactId>
<artifactId>spring-ai-cassandra-store</artifactId>
<packaging>jar</packaging>
<name>Spring AI Vector Store Apache Cassandra</name>
<description>Spring AI Vector Store for Apache Cassandra</description>

View File

@@ -29,9 +29,7 @@ import org.springframework.ai.document.Document;
import org.springframework.ai.embedding.EmbeddingClient;
import org.springframework.ai.vectorstore.filter.FilterExpressionConverter;
import org.springframework.ai.vectorstore.filter.converter.ChromaFilterExpressionConverter;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.lang.NonNull;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
@@ -42,10 +40,8 @@ import org.springframework.util.StringUtils;
* their similarity to a query, using the {@link ChromaApi} and {@link EmbeddingClient}
* for embedding calculations. For more information about how it does this, see the
* official <a href="https://www.trychroma.com/">Chroma website</a>.
*
* @author Christian Tzolov
*/
public class ChromaVectorStore implements VectorStore, ApplicationListener<ApplicationReadyEvent> {
public class ChromaVectorStore implements VectorStore, InitializingBean {
public static final String DISTANCE_FIELD_NAME = "distance";
@@ -151,7 +147,7 @@ public class ChromaVectorStore implements VectorStore, ApplicationListener<Appli
}
@Override
public void onApplicationEvent(@NonNull ApplicationReadyEvent event) {
public void afterPropertiesSet() throws Exception {
var collection = this.chromaApi.getCollection(this.collectionName);
if (collection == null) {
collection = this.chromaApi.createCollection(new ChromaApi.CreateCollectionRequest(this.collectionName));
@@ -159,4 +155,4 @@ public class ChromaVectorStore implements VectorStore, ApplicationListener<Appli
this.collectionId = collection.id();
}
}
}

View File

@@ -37,8 +37,7 @@ import org.springframework.ai.document.Document;
import org.springframework.ai.embedding.EmbeddingClient;
import org.springframework.ai.vectorstore.filter.Filter;
import org.springframework.ai.vectorstore.filter.FilterExpressionConverter;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;
import java.io.IOException;
@@ -50,10 +49,9 @@ import java.util.stream.Collectors;
/**
* @author Jemin Huh
* @author Wei Jiang
* @author Josh Long
* @since 1.0.0
*/
public class ElasticsearchVectorStore implements VectorStore, ApplicationListener<ApplicationReadyEvent> {
public class ElasticsearchVectorStore implements VectorStore, InitializingBean {
// divided by 2 to get score in the range [0, 1]
public static final String COSINE_SIMILARITY_FUNCTION = "(cosineSimilarity(params.query_vector, 'embedding') + 1.0) / 2";
@@ -221,10 +219,10 @@ public class ElasticsearchVectorStore implements VectorStore, ApplicationListene
}
@Override
public void onApplicationEvent(ApplicationReadyEvent event) {
public void afterPropertiesSet() {
if (!indexExists()) {
createIndexMapping();
}
}
}
}

View File

@@ -8,7 +8,7 @@
<version>1.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<artifactId>spring-ai-gemfire</artifactId>
<artifactId>spring-ai-gemfire-store</artifactId>
<packaging>jar</packaging>
<name>Spring AI Vector Store - GemFire</name>
<description>Spring AI GemFire Vector Store</description>

View File

@@ -55,16 +55,14 @@ import org.springframework.ai.document.Document;
import org.springframework.ai.embedding.EmbeddingClient;
import org.springframework.ai.vectorstore.filter.FilterExpressionConverter;
import org.springframework.ai.vectorstore.filter.converter.MilvusFilterExpressionConverter;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* @author Christian Tzolov
* @author Josh Long
*/
public class MilvusVectorStore implements VectorStore, ApplicationListener<ApplicationReadyEvent> {
public class MilvusVectorStore implements VectorStore, InitializingBean {
private static final Logger logger = LoggerFactory.getLogger(MilvusVectorStore.class);
@@ -98,11 +96,6 @@ public class MilvusVectorStore implements VectorStore, ApplicationListener<Appli
private final MilvusVectorStoreConfig config;
@Override
public void onApplicationEvent(ApplicationReadyEvent event) {
this.createCollection();
}
/**
* Configuration for the Milvus vector store.
*/
@@ -385,6 +378,10 @@ public class MilvusVectorStore implements VectorStore, ApplicationListener<Appli
// ---------------------------------------------------------------------------------
// Initialization
// ---------------------------------------------------------------------------------
@Override
public void afterPropertiesSet() throws Exception {
this.createCollection();
}
void releaseCollection() {
if (isDatabaseCollectionExists()) {

View File

@@ -25,8 +25,7 @@ import com.mongodb.BasicDBObject;
import org.springframework.ai.document.Document;
import org.springframework.ai.embedding.EmbeddingClient;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.query.Criteria;
@@ -37,10 +36,9 @@ import static org.springframework.data.mongodb.core.query.Criteria.where;
/**
* @author Chris Smith
* @author Josh Long
* @since 1.0.0
*/
public class MongoDBAtlasVectorStore implements VectorStore, ApplicationListener<ApplicationReadyEvent> {
public class MongoDBAtlasVectorStore implements VectorStore, InitializingBean {
public static final String ID_FIELD_NAME = "_id";
@@ -78,6 +76,16 @@ public class MongoDBAtlasVectorStore implements VectorStore, ApplicationListener
}
@Override
public void afterPropertiesSet() throws Exception {
// Create the collection if it does not exist
if (!mongoTemplate.collectionExists(this.config.collectionName)) {
mongoTemplate.createCollection(this.config.collectionName);
}
// Create search index, command doesn't do anything if already existing
mongoTemplate.executeCommand(createSearchIndex());
}
/**
* Provides the Definition for the search index
*/
@@ -166,16 +174,6 @@ public class MongoDBAtlasVectorStore implements VectorStore, ApplicationListener
.toList();
}
@Override
public void onApplicationEvent(ApplicationReadyEvent event) {
// Create the collection if it does not exist
if (!mongoTemplate.collectionExists(this.config.collectionName)) {
mongoTemplate.createCollection(this.config.collectionName);
}
// Create search index, command doesn't do anything if already existing
mongoTemplate.executeCommand(createSearchIndex());
}
public static class MongoDBVectorStoreConfig {
private final String collectionName;

View File

@@ -22,8 +22,7 @@ import org.neo4j.driver.Values;
import org.springframework.ai.document.Document;
import org.springframework.ai.embedding.EmbeddingClient;
import org.springframework.ai.vectorstore.filter.Neo4jVectorFilterExpressionConverter;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;
import java.util.HashMap;
@@ -35,9 +34,8 @@ import java.util.function.Predicate;
/**
* @author Gerrit Meier
* @author Michael Simons
* @author Josh Long
*/
public class Neo4jVectorStore implements VectorStore, ApplicationListener<ApplicationReadyEvent> {
public class Neo4jVectorStore implements VectorStore, InitializingBean {
/**
* An enum to configure the distance function used in the Neo4j vector index.
@@ -72,7 +70,6 @@ public class Neo4jVectorStore implements VectorStore, ApplicationListener<Applic
private final String indexName;
// needed for similarity search call
private final String indexNameNotSanitized;
private final String idProperty;
@@ -256,29 +253,6 @@ public class Neo4jVectorStore implements VectorStore, ApplicationListener<Applic
}
@Override
public void onApplicationEvent(ApplicationReadyEvent event) {
try (var session = this.driver.session(this.config.sessionConfig)) {
session
.run("CREATE CONSTRAINT %s IF NOT EXISTS FOR (n:%s) REQUIRE n.%s IS UNIQUE"
.formatted(this.config.constraintName, this.config.label, this.config.idProperty))
.consume();
var statement = """
CREATE VECTOR INDEX %s IF NOT EXISTS FOR (n:%s) ON (n.%s)
OPTIONS {indexConfig: {
`vector.dimensions`: %d,
`vector.similarity_function`: '%s'
}}
""".formatted(this.config.indexName, this.config.label, this.config.embeddingProperty,
this.config.embeddingDimension, this.config.distanceType.name);
session.run(statement).consume();
session.run("CALL db.awaitIndexes()").consume();
}
}
public static final int DEFAULT_EMBEDDING_DIMENSION = 1536;
public static final String DEFAULT_LABEL = "Document";
@@ -374,6 +348,29 @@ public class Neo4jVectorStore implements VectorStore, ApplicationListener<Applic
}
}
@Override
public void afterPropertiesSet() {
try (var session = this.driver.session(this.config.sessionConfig)) {
session
.run("CREATE CONSTRAINT %s IF NOT EXISTS FOR (n:%s) REQUIRE n.%s IS UNIQUE"
.formatted(this.config.constraintName, this.config.label, this.config.idProperty))
.consume();
var statement = """
CREATE VECTOR INDEX %s IF NOT EXISTS FOR (n:%s) ON (n.%s)
OPTIONS {indexConfig: {
`vector.dimensions`: %d,
`vector.similarity_function`: '%s'
}}
""".formatted(this.config.indexName, this.config.label, this.config.embeddingProperty,
this.config.embeddingDimension, this.config.distanceType.name);
session.run(statement).consume();
session.run("CALL db.awaitIndexes()").consume();
}
}
private Map<String, Object> documentToRecord(Document document) {
var embedding = this.embeddingClient.embed(document);
document.setEmbedding(embedding);
@@ -416,4 +413,4 @@ public class Neo4jVectorStore implements VectorStore, ApplicationListener<Applic
Map.copyOf(metaData));
}
}
}

View File

@@ -35,8 +35,7 @@ import org.springframework.ai.document.Document;
import org.springframework.ai.embedding.EmbeddingClient;
import org.springframework.ai.vectorstore.filter.FilterExpressionConverter;
import org.springframework.ai.vectorstore.filter.converter.PgVectorFilterExpressionConverter;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.jdbc.core.BatchPreparedStatementSetter;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
@@ -50,9 +49,8 @@ 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, ApplicationListener<ApplicationReadyEvent> {
public class PgVectorStore implements VectorStore, InitializingBean {
private static final Logger logger = LoggerFactory.getLogger(PgVectorStore.class);
@@ -80,40 +78,6 @@ public class PgVectorStore implements VectorStore, ApplicationListener<Applicati
private PgIndexType createIndexMethod;
@Override
public void onApplicationEvent(ApplicationReadyEvent event) {
try {
// 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");
this.jdbcTemplate.execute("CREATE EXTENSION IF NOT EXISTS \"uuid-ossp\"");
// Remove existing VectorStoreTable
if (this.removeExistingVectorStoreTable) {
this.jdbcTemplate.execute("DROP TABLE IF EXISTS " + VECTOR_TABLE_NAME);
}
this.jdbcTemplate.execute(String.format("""
CREATE TABLE IF NOT EXISTS %s (
id uuid DEFAULT uuid_generate_v4() PRIMARY KEY,
content text,
metadata json,
embedding vector(%d)
)
""", VECTOR_TABLE_NAME, this.embeddingDimensions()));
if (this.createIndexMethod != PgIndexType.NONE) {
this.jdbcTemplate.execute(String.format("""
CREATE INDEX IF NOT EXISTS %s ON %s USING %s (embedding %s)
""", VECTOR_INDEX_NAME, VECTOR_TABLE_NAME, this.createIndexMethod,
this.getDistanceType().index));
}
}
catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* By default, pgvector performs exact nearest neighbor search, which provides perfect
* recall. You can add an index to use approximate nearest neighbor search, which
@@ -367,6 +331,33 @@ public class PgVectorStore implements VectorStore, ApplicationListener<Applicati
// ---------------------------------------------------------------------------------
// Initialize
// ---------------------------------------------------------------------------------
@Override
public void afterPropertiesSet() throws Exception {
// 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");
this.jdbcTemplate.execute("CREATE EXTENSION IF NOT EXISTS \"uuid-ossp\"");
// Remove existing VectorStoreTable
if (this.removeExistingVectorStoreTable) {
this.jdbcTemplate.execute("DROP TABLE IF EXISTS " + VECTOR_TABLE_NAME);
}
this.jdbcTemplate.execute(String.format("""
CREATE TABLE IF NOT EXISTS %s (
id uuid DEFAULT uuid_generate_v4() PRIMARY KEY,
content text,
metadata json,
embedding vector(%d)
)
""", VECTOR_TABLE_NAME, this.embeddingDimensions()));
if (this.createIndexMethod != PgIndexType.NONE) {
this.jdbcTemplate.execute(String.format("""
CREATE INDEX IF NOT EXISTS %s ON %s USING %s (embedding %s)
""", VECTOR_INDEX_NAME, VECTOR_TABLE_NAME, this.createIndexMethod, this.getDistanceType().index));
}
}
int embeddingDimensions() {
// The manually set dimensions have precedence over the computed one.

View File

@@ -8,7 +8,7 @@
<version>1.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<artifactId>spring-ai-pinecone</artifactId>
<artifactId>spring-ai-pinecone-store</artifactId>
<packaging>jar</packaging>
<name>Spring AI Vector Store - Pinecone </name>
<url>https://github.com/spring-projects/spring-ai</url>

View File

@@ -8,7 +8,7 @@
<version>1.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<artifactId>spring-ai-qdrant</artifactId>
<artifactId>spring-ai-qdrant-store</artifactId>
<packaging>jar</packaging>
<name>Spring AI Vector Store - QDrant</name>

View File

@@ -15,12 +15,24 @@
*/
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.EmbeddingClient;
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;
@@ -32,19 +44,6 @@ 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.EmbeddingClient;
import org.springframework.ai.vectorstore.SearchRequest;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.ApplicationListener;
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,
* and similarity searching of documents in a Qdrant collection.
@@ -52,10 +51,9 @@ import static io.qdrant.client.WithPayloadSelectorFactory.enable;
* @author Anush Shetty
* @author Christian Tzolov
* @author Eddú Meléndez
* @author Josh Long
* @since 0.8.1
*/
public class QdrantVectorStore implements VectorStore, ApplicationListener<ApplicationReadyEvent> {
public class QdrantVectorStore implements VectorStore, InitializingBean {
private static final String CONTENT_FIELD_NAME = "doc_content";
@@ -86,7 +84,6 @@ public class QdrantVectorStore implements VectorStore, ApplicationListener<Appli
*
* @param builder The configuration builder.
*/
private QdrantVectorStoreConfig(Builder builder) {
this.collectionName = builder.collectionName;
}
@@ -161,24 +158,6 @@ public class QdrantVectorStore implements VectorStore, ApplicationListener<Appli
this.qdrantClient = qdrantClient;
}
@Override
public void onApplicationEvent(ApplicationReadyEvent event) {
// Create the collection if it does not exist.
if (!isCollectionExists()) {
var vectorParams = VectorParams.newBuilder()
.setDistance(Distance.Cosine)
.setSize(this.embeddingClient.dimensions())
.build();
try {
this.qdrantClient.createCollectionAsync(this.collectionName, vectorParams).get();
} //
catch (Exception e) {
throw new RuntimeException(e);
}
}
}
/**
* Adds a list of documents to the vector store.
* @param documents The list of documents to be added.
@@ -261,6 +240,7 @@ public class QdrantVectorStore implements VectorStore, ApplicationListener<Appli
/**
* Extracts metadata from a Protobuf Struct.
* @param metadataStruct The Protobuf Struct containing metadata.
* @return The metadata as a map.
*/
private Document toDocument(ScoredPoint point) {
@@ -304,6 +284,18 @@ public class QdrantVectorStore implements VectorStore, ApplicationListener<Appli
return doubleList.stream().map(d -> d.floatValue()).toList();
}
@Override
public void afterPropertiesSet() throws Exception {
// Create the collection if it does not exist.
if (!isCollectionExists()) {
var vectorParams = VectorParams.newBuilder()
.setDistance(Distance.Cosine)
.setSize(this.embeddingClient.dimensions())
.build();
this.qdrantClient.createCollectionAsync(this.collectionName, vectorParams).get();
}
}
private boolean isCollectionExists() {
try {
return this.qdrantClient.listCollectionsAsync().get().stream().anyMatch(c -> c.equals(this.collectionName));
@@ -313,4 +305,4 @@ public class QdrantVectorStore implements VectorStore, ApplicationListener<Appli
}
}
}
}

View File

@@ -8,7 +8,7 @@
<version>1.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<artifactId>spring-ai-redis</artifactId>
<artifactId>spring-ai-redis-store</artifactId>
<packaging>jar</packaging>
<name>Spring AI Vector Store - Redis </name>
<description>Spring AI Vector Store - Redis </description>

View File

@@ -28,6 +28,13 @@ import java.util.stream.Collectors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ai.document.Document;
import org.springframework.ai.embedding.EmbeddingClient;
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;
@@ -44,14 +51,6 @@ import redis.clients.jedis.search.schemafields.TextField;
import redis.clients.jedis.search.schemafields.VectorField;
import redis.clients.jedis.search.schemafields.VectorField.VectorAlgorithm;
import org.springframework.ai.document.Document;
import org.springframework.ai.embedding.EmbeddingClient;
import org.springframework.ai.vectorstore.filter.FilterExpressionConverter;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
/**
* The RedisVectorStore is for managing and querying vector data in a Redis database. It
* offers functionalities like adding, deleting, and performing similarity searches on
@@ -69,27 +68,11 @@ import org.springframework.util.CollectionUtils;
*
* @author Julien Ruaux
* @author Christian Tzolov
* @author Josh Long
* @see VectorStore
* @see RedisVectorStoreConfig
* @see EmbeddingClient
*/
public class RedisVectorStore implements VectorStore, ApplicationListener<ApplicationReadyEvent> {
@Override
public void onApplicationEvent(ApplicationReadyEvent event) {
// If index already exists don't do anything
if (this.jedis.ftList().contains(this.config.indexName)) {
return;
}
String response = this.jedis.ftCreate(this.config.indexName,
FTCreateParams.createParams().on(IndexDataType.JSON).addPrefix(this.config.prefix), schemaFields());
if (!RESPONSE_OK.test(response)) {
String message = MessageFormat.format("Could not create index: {0}", response);
throw new RuntimeException(message);
}
}
public class RedisVectorStore implements VectorStore, InitializingBean {
public enum Algorithm {
@@ -419,6 +402,22 @@ public class RedisVectorStore implements VectorStore, ApplicationListener<Applic
return "(" + this.filterExpressionConverter.convertExpression(request.getFilterExpression()) + ")";
}
@Override
public void afterPropertiesSet() {
// If index already exists don't do anything
if (this.jedis.ftList().contains(this.config.indexName)) {
return;
}
String response = this.jedis.ftCreate(this.config.indexName,
FTCreateParams.createParams().on(IndexDataType.JSON).addPrefix(this.config.prefix), schemaFields());
if (!RESPONSE_OK.test(response)) {
String message = MessageFormat.format("Could not create index: {0}", response);
throw new RuntimeException(message);
}
}
private Iterable<SchemaField> schemaFields() {
Map<String, Object> vectorAttrs = new HashMap<>();
vectorAttrs.put("DIM", this.embeddingClient.dimensions());
@@ -476,4 +475,4 @@ public class RedisVectorStore implements VectorStore, ApplicationListener<Applic
return embeddingFloat;
}
}
}

View File

@@ -551,4 +551,4 @@ public class WeaviateVectorStore implements VectorStore, InitializingBean {
this.delete(List.of(document.getId()));
}
}
}