Skip to content

Commit ea0b439

Browse files
Anush008tzolov
authored andcommitted
Implement Qdrant vector store
- Implement QdrantVectorStore. Uses a custom parser for converting Spring AI metadata(Map<String, Object>) to Qdrant GRPC payload. - Implement Qdrant Expression Filter support. Uses a custom parser for converting Spring AI filters to Qdrant-compatible GRPC filters. - Add ITs using testcontainers. - Add antora docs adrant.adoc. - Add Qdrant vector store auto-configuraton and boot starter. Additional (review) change: - Fix poms parent to 0.8.1-SNAPSHOT. - Rename ObjectFactory into QdrantObjectFactor. - Rename ValueFactory into QdrantValueFactory. - Move the org.springframework.ai.vectorstore package into org.springframework.ai.vectorstore.qdrant. - Add missing Autoconfigure definition. - Add missing license and JavaDocs. - Minor code style improvmentes. - Move the qdrant version to the main pom - Add QdrantVectorStoreAutoConfigurationIT - Remove guava dependency - Improve gdrant.adoc conent and structure. - Remove the grpc-protobuf dependency Resolves #331
1 parent e1462b8 commit ea0b439

File tree

21 files changed

+1686
-3
lines changed

21 files changed

+1686
-3
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ Though the `DocumentWriter` interface isn't exclusively for Vector Database writ
162162

163163
**Vector Stores:** Vector Databases are instrumental in incorporating your data with AI models.
164164
They ascertain which document sections the AI should use for generating responses.
165-
Examples of Vector Databases include Chroma, Postgres, Pinecone, Weaviate, Mongo Atlas, and Redis. Spring AI's `VectorStore` abstraction permits effortless transitions between database implementations.
165+
Examples of Vector Databases include Chroma, Postgres, Pinecone, Qdrant, Weaviate, Mongo Atlas, and Redis. Spring AI's `VectorStore` abstraction permits effortless transitions between database implementations.
166166

167167

168168

pom.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
<module>spring-ai-spring-boot-starters/spring-ai-starter-redis</module>
4242
<module>spring-ai-spring-boot-starters/spring-ai-starter-stability-ai</module>
4343
<module>spring-ai-spring-boot-starters/spring-ai-starter-neo4j-store</module>
44+
<module>spring-ai-spring-boot-starters/spring-ai-starter-qdrant-store</module>
4445
<module>spring-ai-spring-boot-starters/spring-ai-starter-postgresml-embedding</module>
4546
<module>spring-ai-docs</module>
4647
<module>vector-stores/spring-ai-pgvector-store</module>
@@ -55,6 +56,7 @@
5556
<module>vector-stores/spring-ai-redis</module>
5657
<module>spring-ai-spring-boot-starters/spring-ai-starter-vertex-ai-palm2</module>
5758
<module>spring-ai-spring-boot-starters/spring-ai-starter-vertex-ai-gemini</module>
59+
<module>vector-stores/spring-ai-qdrant</module>
5860
<module>spring-ai-spring-boot-starters/spring-ai-starter-bedrock-ai</module>
5961
<module>spring-ai-spring-boot-starters/spring-ai-starter-mistral-ai</module>
6062
</modules>
@@ -112,6 +114,7 @@
112114
<djl.version>0.26.0</djl.version>
113115
<onnxruntime.version>1.17.0</onnxruntime.version>
114116
<com.google.cloud.version>26.33.0</com.google.cloud.version>
117+
<qdrant.version>1.7.1</qdrant.version>
115118

116119
<!-- Protobuf -->
117120
<protobuf-java.version>3.25.2</protobuf-java.version>
@@ -125,6 +128,7 @@
125128
<fastjson.version>2.0.46</fastjson.version>
126129
<azure-search.version>11.6.1</azure-search.version>
127130
<weaviate-client.version>4.5.1</weaviate-client.version>
131+
<qdrant.version>1.7.1</qdrant.version>
128132

129133
<!-- testing dependencies -->
130134
<testcontainers.version>1.19.6</testcontainers.version>

spring-ai-bom/pom.xml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,12 @@
161161
<version>${project.version}</version>
162162
</dependency>
163163

164+
<dependency>
165+
<groupId>org.springframework.ai</groupId>
166+
<artifactId>spring-ai-qdrant</artifactId>
167+
<version>${project.version}</version>
168+
</dependency>
169+
164170
<!-- Utilities -->
165171
<dependency>
166172
<groupId>org.springframework.ai</groupId>
@@ -283,6 +289,11 @@
283289
<version>${project.version}</version>
284290
</dependency>
285291

292+
<dependency>
293+
<groupId>org.springframework.ai</groupId>
294+
<artifactId>spring-ai-qdrant-store-spring-boot-starter</artifactId>
295+
<version>${project.version}</version>
296+
</dependency>
286297
</dependencies>
287298
</dependencyManagement>
288299

spring-ai-docs/src/main/antora/modules/ROOT/nav.adoc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
*** xref:api/vectordbs/weaviate.adoc[]
4444
*** xref:api/vectordbs/redis.adoc[]
4545
*** xref:api/vectordbs/pinecone.adoc[]
46+
*** xref:api/vectordbs/qdrant.adoc[]
4647
** xref:api/etl-pipeline.adoc[]
4748
** xref:api/testing.adoc[]
4849
** xref:api/generic-model.adoc[]

spring-ai-docs/src/main/antora/modules/ROOT/pages/api/vectordbs.adoc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ These are the available implementations of the `VectorStore` interface:
9393
* xref:api/vectordbs/neo4j.adoc[Neo4jVectorStore] - The https://neo4j.com/[Neo4j] vector store.
9494
* xref:api/vectordbs/pgvector.adoc[PgVectorStore] - The https://github.com/pgvector/pgvector[PostgreSQL/PGVector] vector store.
9595
* xref:api/vectordbs/pinecone.adoc[PineconeVectorStore] - https://www.pinecone.io/[PineCone] vector store.
96+
* xref:api/vectordbs/qdrant.adoc[QdrantVectorStore] - https://www.qdrant.tech/[Qdrant] vector store.
9697
* xref:api/vectordbs/redis.adoc[RedisVectorStore] - The https://redis.io/[Redis] vector store.
9798
* xref:api/vectordbs/weaviate.adoc[WeaviateVectorStore] - The https://weaviate.io/[Weaviate] vector store.
9899
* link:https://github.com/spring-projects/spring-ai/blob/main/spring-ai-core/src/main/java/org/springframework/ai/vectorstore/SimpleVectorStore.java[SimpleVectorStore] - A simple implementation of persistent vector storage, good for educational purposes.
Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
= Qdrant
2+
3+
This section walks you through setting up the Qdrant `VectorStore` to store document embeddings and perform similarity searches.
4+
5+
link:https://www.qdrant.tech/[Qdrant] is an open-source, high-performance vector search engine/database.
6+
7+
== Prerequisites
8+
9+
* Qdrant Instance: Set up a Qdrant instance by following the link:https://qdrant.tech/documentation/guides/installation/[installation instructions] in the Qdrant documentation.
10+
* If required, an API key for the xref:api/embeddings.adoc#available-implementations[EmbeddingClient] to generate the embeddings stored by the `QdrantVectorStore`.
11+
12+
== Configuration
13+
14+
To set up `QdrantVectorStore`, you'll need the following information from your Qdrant instance:
15+
16+
* Qdrant Host
17+
* Qdrant GRPC Port
18+
* Qdrant Collection Name
19+
* Optional Qdrant API Key (not required for local development)
20+
21+
[NOTE]
22+
====
23+
A Qdrant collection has to be link:https://qdrant.tech/documentation/concepts/collections/#create-a-collection[created] in advance with the appropriate dimensions and configurations.
24+
25+
For example if using the OpenAI `text-embedding-ada-002` embedding model, create a collection with a vector size of `1536`.
26+
====
27+
28+
== Dependencies
29+
30+
* The Vector Store requires an `EmbeddingClient` instance to calculate embeddings for the documents.
31+
You can pick one of the available xref:api/embeddings.adoc#available-implementations[EmbeddingClient Implementations]. For example ou can use the OpenAI boot starter:
32+
33+
[source,xml]
34+
----
35+
<dependency>
36+
<groupId>org.springframework.ai</groupId>
37+
<artifactId>spring-ai-openai-spring-boot-starter</artifactId>
38+
</dependency>
39+
----
40+
41+
or to your Gradle `build.gradle` build file.
42+
43+
[source,groovy]
44+
----
45+
dependencies {
46+
implementation 'org.springframework.ai:spring-ai-openai-spring-boot-starter'
47+
}
48+
----
49+
50+
TIP: Additionally, you'll need to provide your OpenAI API Key. Set it as an environment variable like so:
51+
`export SPRING_AI_OPENAI_API_KEY='Your_OpenAI_API_Key`
52+
53+
54+
* Add the Qdrant Boot Starter dependency to your project:
55+
56+
[source,xml]
57+
----
58+
<dependency>
59+
<groupId>org.springframework.ai</groupId>
60+
<artifactId>spring-ai-qdrant-store-spring-boot-starter</artifactId>
61+
</dependency>
62+
----
63+
64+
or to your Gradle `build.gradle` build file.
65+
66+
[source,groovy]
67+
----
68+
dependencies {
69+
implementation 'org.springframework.ai:spring-ai-qdrant-store-spring-boot-starter'
70+
}
71+
----
72+
73+
TIP: Refer to the xref:getting-started.adoc#dependency-management[Dependency Management] section to add the Spring AI BOM to your build file.
74+
75+
Please have a look at the list of xref:#qdrant-vectorstore-properties[configuration parameters] for the vector store to learn about the default values and configuration options.
76+
77+
TIP: Refer to the xref:getting-started.adoc#repositories[Repositories] section to add Milestone and/or Snapshot Repositories to your build file.
78+
79+
80+
Now you can Auto-wire the Qdrant Vector Store in your application and use it
81+
82+
[source,java]
83+
----
84+
@Autowired
85+
VectorStore vectorStore;
86+
87+
...
88+
List <Document> documents = List.of(
89+
new Document("Spring AI rocks!! Spring AI rocks!! Spring AI rocks!! Spring AI rocks!! Spring AI rocks!!", Map.of("meta1", "meta1")),
90+
new Document("The World is Big and Salvation Lurks Around the Corner"),
91+
new Document("You walk forward facing the past and you turn back toward the future.", Map.of("meta2", "meta2")));
92+
93+
// Add the documents to Qdrant
94+
vectorStore.add(List.of(document));
95+
96+
// Retrieve documents similar to a query
97+
List<Document> results = vectorStore.similaritySearch(SearchRequest.query("Spring").withTopK(5));
98+
----
99+
100+
== Configuration
101+
102+
To connect to Qdrant and use the `QdrantVectorStore`, you need to provide access details for your instance.
103+
A simple configuration can either be provided via Spring Boot's _application.properties_,
104+
105+
[source,properties]
106+
----
107+
spring.ai.vectorstore.qdrant.host=<host of your qdrant instance>
108+
spring.ai.vectorstore.qdrant.port=<port of your qdrant instance>
109+
spring.ai.vectorstore.qdrant.api-key=<your api key>
110+
spring.ai.vectorstore.qdrant.collection-name=<The name of the collection to use in Qdrant>
111+
112+
# API key if needed, e.g. OpenAI
113+
spring.ai.openai.api.key=<api-key>
114+
----
115+
116+
117+
== Manual Configuration
118+
119+
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:
120+
121+
[source,xml]
122+
----
123+
<dependency>
124+
<groupId>org.springframework.ai</groupId>
125+
<artifactId>spring-ai-qdrant</artifactId>
126+
</dependency>
127+
----
128+
129+
or to your Gradle `build.gradle` build file.
130+
131+
[source,groovy]
132+
----
133+
dependencies {
134+
implementation 'org.springframework.ai:spring-ai-qdrant'
135+
}
136+
----
137+
138+
To configure Qdrant in your application, you can use the following setup:
139+
140+
[source,java]
141+
----
142+
@Bean
143+
public QdrantVectorStoreConfig qdrantVectorStoreConfig() {
144+
145+
return QdrantVectorStoreConfig.builder()
146+
.withHost("<QDRANT_HOSTNAME>")
147+
.withPort(<QDRANT_GRPC_PORT>)
148+
.withCollectionName("<QDRANT_COLLECTION_NAME>")
149+
.withApiKey("<QDRANT_API_KEY>")
150+
.build();
151+
}
152+
----
153+
154+
Integrate with OpenAI's embeddings by adding the Spring Boot OpenAI starter to your project.
155+
This provides you with an implementation of the Embeddings client:
156+
157+
[source,java]
158+
----
159+
@Bean
160+
public VectorStore vectorStore(QdrantVectorStoreConfig config, EmbeddingClient embeddingClient) {
161+
return new QdrantVectorStore(config, embeddingClient);
162+
}
163+
----
164+
165+
=== Metadata filtering
166+
167+
You can leverage the generic, portable link:https://docs.spring.io/spring-ai/reference/api/vectordbs.html#_metadata_filters[metadata filters] with the Qdrant vector store.
168+
169+
For example, you can use either the text expression language:
170+
171+
[source,java]
172+
----
173+
vectorStore.similaritySearch(
174+
SearchRequest.defaults()
175+
.withQuery("The World")
176+
.withTopK(TOP_K)
177+
.withSimilarityThreshold(SIMILARITY_THRESHOLD)
178+
.withFilterExpression("author in ['john', 'jill'] && article_type == 'blog'"));
179+
----
180+
181+
or programmatically using the `Filter.Expression` DSL:
182+
183+
[source,java]
184+
----
185+
FilterExpressionBuilder b = new FilterExpressionBuilder();
186+
187+
vectorStore.similaritySearch(SearchRequest.defaults()
188+
.withQuery("The World")
189+
.withTopK(TOP_K)
190+
.withSimilarityThreshold(SIMILARITY_THRESHOLD)
191+
.withFilterExpression(b.and(
192+
b.in("john", "jill"),
193+
b.eq("article_type", "blog")).build()));
194+
----
195+
196+
NOTE: These filter expressions are converted into the equivalent Qdrant link:https://qdrant.tech/documentation/concepts/filtering/[filters].
197+
198+
199+
[[qdrant-vectorstore-properties]]
200+
== Qdrant VectorStore properties
201+
202+
You can use the following properties in your Spring Boot configuration to customize the Qdrant vector store.
203+
204+
|===
205+
|Property| Description | Default value
206+
207+
|`spring.ai.vectorstore.qdrant.host`| The host of the Qdrant server. | localhost
208+
|`spring.ai.vectorstore.qdrant.port`| The port of the Qdrant server. | 6334
209+
|`spring.ai.vectorstore.qdrant.api-key`| The API key to use for authentication with the Qdrant server. | -
210+
|`spring.ai.vectorstore.qdrant.collection-name`| The name of the collection to use in Qdrant. | -
211+
|`spring.ai.vectorstore.qdrant.use-tls`| Whether to use TLS(HTTPS). Defaults to false. | false
212+
|===

spring-ai-docs/src/main/antora/modules/ROOT/pages/getting-started.adoc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,7 @@ Each of the following sections in the documentation shows which dependencies you
164164
** xref:api/vectordbs/neo4j.adoc[Neo4jVectorStore] - The https://neo4j.com/[Neo4j] vector store.
165165
** xref:api/vectordbs/pgvector.adoc[PgVectorStore] - The https://github.com/pgvector/pgvector[PostgreSQL/PGVector] vector store.
166166
** xref:api/vectordbs/pinecone.adoc[PineconeVectorStore] - https://www.pinecone.io/[PineCone] vector store.
167+
** xref:api/vectordbs/qdrant.adoc[QdrantVectorStore] - https://www.qdrant.tech/[Qdrant] vector store.
167168
** xref:api/vectordbs/redis.adoc[RedisVectorStore] - The https://redis.io/[Redis] vector store.
168169
** xref:api/vectordbs/weaviate.adoc[WeaviateVectorStore] - The https://weaviate.io/[Weaviate] vector store.
169170
** link:https://github.com/spring-projects/spring-ai/blob/main/spring-ai-core/src/main/java/org/springframework/ai/vectorstore/SimpleVectorStore.java[SimpleVectorStore] - A simple (in-memory) implementation of persistent vector storage, good for educational purposes.

spring-ai-docs/src/main/antora/modules/ROOT/pages/index.adoc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ Spring AI provides the following features:
1515
* Supported Model types are Chat and Text to Image with more on the way.
1616
* Portable API across AI providers for Chat and for Embedding models. Both synchronous and stream API options are supported. Dropping down to access model specific features is also supported.
1717
* Mapping of AI Model output to POJOs.
18-
* Support for all major Vector Database providers such as Azure Vector Search, Chroma, Milvus, Neo4j, PostgreSQL/PGVector, PineCone, Redis, and Weaviate
18+
* Support for all major Vector Database providers such as Azure Vector Search, Chroma, Milvus, Neo4j, PostgreSQL/PGVector, PineCone, Qdrant, Redis, and Weaviate
1919
* Portable API across Vector Store providers, including a novel SQL-like metadata filter API that is also portable.
2020
* Function calling
2121
* Spring Boot Auto Configuration and Starters for AI Models and Vector Stores.

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

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,14 @@
215215
<optional>true</optional>
216216
</dependency>
217217

218+
<!-- Qdrant Vector Store-->
219+
<dependency>
220+
<groupId>org.springframework.ai</groupId>
221+
<artifactId>spring-ai-qdrant</artifactId>
222+
<version>${project.parent.version}</version>
223+
<optional>true</optional>
224+
</dependency>
225+
218226
<!-- test dependencies -->
219227

220228
<dependency>
@@ -287,6 +295,14 @@
287295
<scope>test</scope>
288296
</dependency>
289297

298+
<dependency>
299+
<groupId>org.testcontainers</groupId>
300+
<artifactId>qdrant</artifactId>
301+
<version>1.19.6</version>
302+
<scope>test</scope>
303+
</dependency>
304+
305+
290306
</dependencies>
291307

292308
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/*
2+
* Copyright 2024-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.qdrant;
18+
19+
import org.springframework.ai.embedding.EmbeddingClient;
20+
import org.springframework.ai.vectorstore.VectorStore;
21+
import org.springframework.ai.vectorstore.qdrant.QdrantVectorStore;
22+
import org.springframework.ai.vectorstore.qdrant.QdrantVectorStore.QdrantVectorStoreConfig;
23+
import org.springframework.boot.autoconfigure.AutoConfiguration;
24+
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
25+
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
26+
import org.springframework.boot.context.properties.EnableConfigurationProperties;
27+
import org.springframework.context.annotation.Bean;
28+
29+
/**
30+
* @author Anush Shetty
31+
* @since 0.8.1
32+
*/
33+
@AutoConfiguration
34+
@ConditionalOnClass({ QdrantVectorStore.class, EmbeddingClient.class })
35+
@EnableConfigurationProperties(QdrantVectorStoreProperties.class)
36+
public class QdrantVectorStoreAutoConfiguration {
37+
38+
@Bean
39+
@ConditionalOnMissingBean
40+
public VectorStore vectorStore(EmbeddingClient embeddingClient, QdrantVectorStoreProperties properties) {
41+
42+
var config = QdrantVectorStoreConfig.builder()
43+
.withCollectionName(properties.getCollectionName())
44+
.withHost(properties.getHost())
45+
.withPort(properties.getPort())
46+
.withTls(properties.useTls())
47+
.withApiKey(properties.getApiKey())
48+
.build();
49+
50+
return new QdrantVectorStore(config, embeddingClient);
51+
}
52+
53+
}

0 commit comments

Comments
 (0)