Skip to content

Commit 41bb6de

Browse files
geetrawatLouis Jacomejhuynh1
authored andcommitted
Adds GemFireVectorStore Auto-Configuration
- Adds spring boot auto-configuration support for GemFireVectorStore - Adds integration test GemFireVectorStoreAutoConfigurationIT - Includes gemfire-testcontainers in integration tests - Adds unit test GemFireVectorStorePropertiesTests - Refactors GemFireVectorStore.java extracting GemFireVectorStoreConfig.java - Renames spring-ai-gemfire to spring-ai-gemfire-store - Adds GemFireConnectionDetails - Adds GemFireVectorStoreProperties with default values Co-authored-by: Louis Jacome <[email protected]> Co-authored-by: Jason Huyn <[email protected]>
1 parent 9e865f0 commit 41bb6de

File tree

16 files changed

+989
-251
lines changed

16 files changed

+989
-251
lines changed

pom.xml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
<module>spring-ai-spring-boot-starters/spring-ai-starter-stability-ai</module>
4747
<module>spring-ai-spring-boot-starters/spring-ai-starter-neo4j-store</module>
4848
<module>spring-ai-spring-boot-starters/spring-ai-starter-qdrant-store</module>
49+
<module>spring-ai-spring-boot-starters/spring-ai-starter-gemfire-store</module>
4950
<module>spring-ai-spring-boot-starters/spring-ai-starter-postgresml-embedding</module>
5051
<module>spring-ai-docs</module>
5152
<module>vector-stores/spring-ai-cassandra</module>
@@ -60,7 +61,7 @@
6061
<module>vector-stores/spring-ai-azure</module>
6162
<module>vector-stores/spring-ai-weaviate</module>
6263
<module>vector-stores/spring-ai-redis</module>
63-
<module>vector-stores/spring-ai-gemfire</module>
64+
<module>vector-stores/spring-ai-gemfire-store</module>
6465
<module>spring-ai-spring-boot-starters/spring-ai-starter-vertex-ai-palm2</module>
6566
<module>spring-ai-spring-boot-starters/spring-ai-starter-vertex-ai-gemini</module>
6667
<module>vector-stores/spring-ai-qdrant</module>

spring-ai-bom/pom.xml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@
206206

207207
<dependency>
208208
<groupId>org.springframework.ai</groupId>
209-
<artifactId>spring-ai-gemfire</artifactId>
209+
<artifactId>spring-ai-gemfire-store</artifactId>
210210
<version>${project.version}</version>
211211
</dependency>
212212

@@ -384,6 +384,12 @@
384384
<artifactId>spring-ai-elasticsearch-store-spring-boot-starter</artifactId>
385385
<version>${project.version}</version>
386386
</dependency>
387+
388+
<dependency>
389+
<groupId>org.springframework.ai</groupId>
390+
<artifactId>spring-ai-gemfire-store-spring-boot-starter</artifactId>
391+
<version>${project.version}</version>
392+
</dependency>
387393
</dependencies>
388394
</dependencyManagement>
389395

Lines changed: 73 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,122 +1,131 @@
11
= GemFire Vector Store
22

3-
This section walks you through setting up the GemFire VectorStore to store document embeddings and perform similarity searches.
3+
This section walks you through setting up the `GemFireVectorStore` to store document embeddings and perform similarity searches.
44

5-
link:https://tanzu.vmware.com/gemfire[GemFire] is an ultra high speed in-memory data and compute grid, with vector extensions to store and search vectors efficiently.
5+
link:https://tanzu.vmware.com/gemfire[GemFire] is a distributed, in-memory, key-value store that performs read and write operations at blazingly fast speeds. It offers highly available parallel message queues, continuous availability, and an event-driven architecture you can scale dynamically with no downtime. As your data size requirements increase to support high-performance, real-time apps, GemFire can scale linearly with ease.
66

7-
link:https://docs.vmware.com/en/VMware-GemFire-VectorDB/1.0/gemfire-vectordb/overview.html[GemFire VectorDB] extends GemFire's capabilities, serving as a versatile vector database that efficiently stores, retrieves, and performs vector searches through a distributed and resilient infrastructure:
8-
9-
Capabilities:
10-
- Create Indexes
11-
- Store vectors and the associated metadata
12-
- Perform vector searches based on similarity
7+
link:https://docs.vmware.com/en/VMware-GemFire-VectorDB/1.0/gemfire-vectordb/overview.html[GemFire VectorDB] extends GemFire's capabilities, serving as a versatile vector database that efficiently stores, retrieves, and performs vector similarity searches.
138

149
== Prerequisites
1510

16-
Access to a GemFire cluster with the link:https://docs.vmware.com/en/VMware-GemFire-VectorDB/1.0/gemfire-vectordb/install.html[GemFire Vector Database] extension installed.
17-
You can download the GemFire VectorDB extension from the link:https://network.pivotal.io/products/gemfire-vectordb/[VMware Tanzu Network] after signing in.
11+
1. A GemFire cluster with the GemFire VectorDB extension enabled
12+
- link:https://docs.vmware.com/en/VMware-GemFire-VectorDB/1.0/gemfire-vectordb/install.html[Install GemFire VectorDB extension]
13+
14+
2. An `EmbeddingClient` bean to compute the document embeddings. Refer to the xref:api/embeddings.adoc#available-implementations[EmbeddingClient] section for more information.
1815

1916
== Dependencies
2017

21-
Add these dependencies to your project:
18+
=== Maven
2219

23-
- Embedding Client boot starter, required for calculating embeddings.
24-
- Transformers Embedding (Local) and follow the ONNX Transformers Embedding instructions.
20+
To use just the `GemFireVectorStore`, add the following dependency to your project’s Maven `pom.xml`:
2521

26-
[source,xml]
22+
[source, xml]
2723
----
2824
<dependency>
29-
<groupId>org.springframework.ai</groupId>
30-
<artifactId>spring-ai-transformers</artifactId>
25+
<groupId>org.springframework.ai</groupId>
26+
<artifactId>spring-ai-gemfire-store</artifactId>
3127
</dependency>
3228
----
3329

34-
- Add the GemFire VectorDB dependencies
30+
To enable Spring Boot’s Auto-Configuration for the `GemFireVectorStore`, also add the following to your project’s Maven `pom.xml`:
3531

36-
[source,xml]
32+
[source, xml]
3733
----
3834
<dependency>
3935
<groupId>org.springframework.ai</groupId>
40-
<artifactId>spring-ai-gemfire</artifactId>
36+
<artifactId>spring-ai-gemfire-store-spring-boot-starter</artifactId>
4137
</dependency>
38+
4239
----
4340

4441

45-
TIP: Refer to the xref:getting-started.adoc#dependency-management[Dependency Management] section to add the Spring AI BOM to your build file.
42+
=== Gradle
4643

44+
For Gradle users, add the following to your `build.gradle` file under the dependencies block to use just the `GemFireVectorStore`:
4745

48-
== Sample Code
46+
[souce, xml]
47+
----
48+
dependencies {
49+
implementation 'org.springframework.ai:spring-ai-gemfire-store'
50+
}
51+
----
4952

50-
- To configure GemFire in your application, use the following setup:
53+
To enable Spring Boot’s Auto-Configuration for the `GemFireVectorStore`, also include this dependency:
5154

52-
[source,java]
55+
[source, xml]
5356
----
54-
@Bean
55-
public GemFireVectorStoreConfig gemFireVectorStoreConfig() {
56-
return GemFireVectorStoreConfig.builder()
57-
.withUrl("http://localhost:8080")
58-
.withIndexName("spring-ai-test-index")
59-
.build();
57+
dependencies {
58+
implementation 'org.springframework.ai:spring-ai-gemfire-store-spring-boot-starter'
6059
}
6160
----
6261

63-
- Create a GemFireVectorStore instance connected to your GemFire VectorDB:
62+
== Usage
63+
64+
- Create a `GemFireVectorStore` instance connected to the GemFire cluster:
6465

6566
[source,java]
6667
----
6768
@Bean
68-
public VectorStore vectorStore(GemFireVectorStoreConfig config, EmbeddingClient embeddingClient) {
69-
return new GemFireVectorStore(config, embeddingClient);
69+
public VectorStore vectorStore(EmbeddingClient embeddingClient) {
70+
return new GemFireVectorStore(new GemFireVectorStoreConfig()
71+
.setIndexName("my-vector-index")
72+
.setPort(7071), embeddingClient);
7073
}
7174
----
72-
- Create a Vector Index which will configure GemFire region.
75+
76+
[NOTE]
77+
====
78+
The default configuration connects to a GemFire cluster at `localhost:8080`
79+
====
80+
81+
- In your application, create a few documents:
7382

7483
[source,java]
7584
----
76-
public void createIndex() {
77-
try {
78-
CreateRequest createRequest = new CreateRequest();
79-
createRequest.setName(INDEX_NAME);
80-
createRequest.setBeamWidth(20);
81-
createRequest.setMaxConnections(16);
82-
ObjectMapper objectMapper = new ObjectMapper();
83-
String index = objectMapper.writeValueAsString(createRequest);
84-
client.post()
85-
.contentType(MediaType.APPLICATION_JSON)
86-
.bodyValue(index)
87-
.retrieve()
88-
.bodyToMono(Void.class)
89-
.block();
90-
}
91-
catch (Exception e) {
92-
logger.warn("An unexpected error occurred while creating the index");
93-
}
94-
}
95-
----
96-
97-
- Create some documents:
85+
List<Document> documents = List.of(
86+
new Document("Spring AI rocks!! Spring AI rocks!! Spring AI rocks!! Spring AI rocks!! Spring AI rocks!!", Map.of("country", "UK", "year", 2020)),
87+
new Document("The World is Big and Salvation Lurks Around the Corner", Map.of()),
88+
new Document("You walk forward facing the past and you turn back toward the future.", Map.of("country", "NL", "year", 2023)));
89+
----
90+
91+
- Add the documents to the vector store:
9892

9993
[source,java]
10094
----
101-
List<Document> documents = List.of(
102-
new Document("1", getText("classpath:/test/data/spring.ai.txt"), Map.of("meta1", "meta1")),
103-
new Document("2", getText("classpath:/test/data/time.shelter.txt"), Map.of()),
104-
new Document("3", getText("classpath:/test/data/great.depression.txt"), Map.of("meta2", "meta2")));
95+
vectorStore.add(documents);
10596
----
10697

107-
- Add the documents to GemFire VectorDB:
98+
- And to retrieve documents using similarity search:
10899

109100
[source,java]
110101
----
111-
vectorStore.add(List.of(document));
102+
List<Document> results = vectorStore.similaritySearch(
103+
SearchRequest.query("Spring").withTopK(5));
112104
----
113105

114-
- And finally, retrieve documents similar to a query:
106+
You should retrieve the document containing the text "Spring AI rocks!!".
115107

108+
You can also limit the number of results using a similarity threshold:
116109
[source,java]
117110
----
118-
List<Document> results = vectorStore.similaritySearch("Spring", 5);
111+
List<Document> results = vectorStore.similaritySearch(
112+
SearchRequest.query("Spring").withTopK(5)
113+
.withSimilarityThreshold(0.5d));
119114
----
120115

121-
If all goes well, you should retrieve the document containing the text "Spring AI rocks!!".
116+
== GemFireVectorStore properties
117+
118+
You can use the following properties in your Spring Boot configuration to further configure the `GemFireVectorStore`.
119+
120+
|===
121+
|Property|Default value
122122

123+
|`spring.ai.vectorstore.gemfire.host`|localhost
124+
|`spring.ai.vectorstore.gemfire.port`|8080
125+
|`spring.ai.vectorstore.gemfire.index-name`|spring-ai-gemfire-store
126+
|`spring.ai.vectorstore.gemfire.beam-width`|100
127+
|`spring.ai.vectorstore.gemfire.max-connections`|16
128+
|`spring.ai.vectorstore.gemfire.vector-similarity-function`|COSINE
129+
|`spring.ai.vectorstore.gemfire.fields`|[]
130+
|`spring.ai.vectorstore.gemfire.buckets`|0
131+
|===

spring-ai-spring-boot-autoconfigure/pom.xml

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,13 @@
1818
<connection>git://github.com/spring-projects/spring-ai.git</connection>
1919
<developerConnection>[email protected]:spring-projects/spring-ai.git</developerConnection>
2020
</scm>
21+
<repositories>
22+
<repository>
23+
<id>gemfire-release-repo</id>
24+
<name>Pivotal GemFire Release Repository</name>
25+
<url>https://commercial-repo.pivotal.io/data3/gemfire-release-repo/gemfire</url>
26+
</repository>
27+
</repositories>
2128

2229
<dependencies>
2330

@@ -267,6 +274,13 @@
267274
<optional>true</optional>
268275
</dependency>
269276

277+
<dependency>
278+
<groupId>org.springframework.ai</groupId>
279+
<artifactId>spring-ai-gemfire-store</artifactId>
280+
<version>${project.parent.version}</version>
281+
<optional>true</optional>
282+
</dependency>
283+
270284
<!-- test dependencies -->
271285

272286
<dependency>
@@ -354,13 +368,18 @@
354368
<scope>test</scope>
355369
</dependency>
356370

371+
<dependency>
372+
<groupId>com.vmware.gemfire</groupId>
373+
<artifactId>gemfire-testcontainers</artifactId>
374+
<version>2.0.0</version>
375+
<scope>test</scope>
376+
</dependency>
357377
<dependency>
358378
<groupId>org.skyscreamer</groupId>
359379
<artifactId>jsonassert</artifactId>
360380
<version>1.5.0</version>
361381
<scope>test</scope>
362382
</dependency>
363-
364-
</dependencies>
383+
</dependencies>
365384

366385
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/*
2+
* Copyright 2023 - 2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.ai.autoconfigure.vectorstore.gemfire;
17+
18+
import org.springframework.boot.autoconfigure.service.connection.ConnectionDetails;
19+
20+
/**
21+
* @author Geet Rawat
22+
*/
23+
public interface GemFireConnectionDetails extends ConnectionDetails {
24+
25+
String getHost();
26+
27+
int getPort();
28+
29+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
/*
2+
* Copyright 2023-2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.ai.autoconfigure.vectorstore.gemfire;
18+
19+
import org.springframework.ai.embedding.EmbeddingClient;
20+
import org.springframework.ai.vectorstore.GemFireVectorStore;
21+
import org.springframework.ai.vectorstore.GemFireVectorStoreConfig;
22+
import org.springframework.boot.autoconfigure.AutoConfiguration;
23+
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
24+
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
25+
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
26+
import org.springframework.boot.context.properties.EnableConfigurationProperties;
27+
import org.springframework.context.annotation.Bean;
28+
29+
/**
30+
* @author Geet Rawat
31+
*/
32+
@AutoConfiguration
33+
@ConditionalOnClass({ GemFireVectorStore.class, EmbeddingClient.class })
34+
@EnableConfigurationProperties(GemFireVectorStoreProperties.class)
35+
@ConditionalOnProperty(prefix = "spring.ai.vectorstore.gemfire", value = { "index-name" })
36+
public class GemFireVectorStoreAutoConfiguration {
37+
38+
@Bean
39+
@ConditionalOnMissingBean(GemFireConnectionDetails.class)
40+
GemFireVectorStoreAutoConfiguration.PropertiesGemFireConnectionDetails gemfireConnectionDetails(
41+
GemFireVectorStoreProperties properties) {
42+
return new GemFireVectorStoreAutoConfiguration.PropertiesGemFireConnectionDetails(properties);
43+
}
44+
45+
@Bean
46+
@ConditionalOnMissingBean
47+
public GemFireVectorStore vectorStore(EmbeddingClient embeddingClient, GemFireVectorStoreProperties properties,
48+
GemFireConnectionDetails gemFireConnectionDetails) {
49+
var config = new GemFireVectorStoreConfig();
50+
51+
config.setHost(gemFireConnectionDetails.getHost())
52+
.setPort(gemFireConnectionDetails.getPort())
53+
.setIndexName(properties.getIndexName())
54+
.setBeamWidth(properties.getBeamWidth())
55+
.setMaxConnections(properties.getMaxConnections())
56+
.setBuckets(properties.getBuckets())
57+
.setVectorSimilarityFunction(properties.getVectorSimilarityFunction())
58+
.setFields(properties.getFields())
59+
.setSslEnabled(properties.isSslEnabled());
60+
return new GemFireVectorStore(config, embeddingClient);
61+
}
62+
63+
private static class PropertiesGemFireConnectionDetails implements GemFireConnectionDetails {
64+
65+
private final GemFireVectorStoreProperties properties;
66+
67+
PropertiesGemFireConnectionDetails(GemFireVectorStoreProperties properties) {
68+
69+
this.properties = properties;
70+
}
71+
72+
@Override
73+
public String getHost() {
74+
return this.properties.getHost();
75+
}
76+
77+
@Override
78+
public int getPort() {
79+
return this.properties.getPort();
80+
}
81+
82+
}
83+
84+
}

0 commit comments

Comments
 (0)