Skip to content

Commit a8110bb

Browse files
committed
Qdrant improvements
- Update docs - Allow colleciton auto-creation if missing - Add cloud IT : QdrantVectorStoreCloudAutoConfigurationIT - Add auto-configuration properties tests: PgVectorStorePropertiesTests
1 parent 41a256c commit a8110bb

File tree

8 files changed

+297
-83
lines changed

8 files changed

+297
-83
lines changed

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

Lines changed: 34 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -9,32 +9,20 @@ link:https://www.qdrant.tech/[Qdrant] is an open-source, high-performance vector
99
* Qdrant Instance: Set up a Qdrant instance by following the link:https://qdrant.tech/documentation/guides/installation/[installation instructions] in the Qdrant documentation.
1010
* If required, an API key for the xref:api/embeddings.adoc#available-implementations[EmbeddingClient] to generate the embeddings stored by the `QdrantVectorStore`.
1111

12-
== Configuration
12+
To set up `QdrantVectorStore`, you'll need the following information from your Qdrant instance: `Host`, `GRPC Port`, `Collection Name`, and `API Key` (if required).
1313

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-
====
14+
NOTE: It is recommended that the Qdrant collection is link:https://qdrant.tech/documentation/concepts/collections/#create-a-collection[created] in advance with the appropriate dimensions and configurations.
15+
If the collection is not created, the `QdrantVectorStore` will attempt to create one using the `Cosine` similarity and the dimension of the configured `EmbeddingClient`.
2716

2817
== Dependencies
2918

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:
19+
Then add the Qdrant boot starter dependency to your project:
3220

3321
[source,xml]
3422
----
3523
<dependency>
3624
<groupId>org.springframework.ai</groupId>
37-
<artifactId>spring-ai-openai-spring-boot-starter</artifactId>
25+
<artifactId>spring-ai-qdrant-store-spring-boot-starter</artifactId>
3826
</dependency>
3927
----
4028

@@ -43,21 +31,20 @@ or to your Gradle `build.gradle` build file.
4331
[source,groovy]
4432
----
4533
dependencies {
46-
implementation 'org.springframework.ai:spring-ai-openai-spring-boot-starter'
34+
implementation 'org.springframework.ai:spring-ai-qdrant-store-spring-boot-starter'
4735
}
4836
----
4937

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-
38+
The Vector Store, also requires an `EmbeddingClient` instance to calculate embeddings for the documents.
39+
You can pick one of the available xref:api/embeddings.adoc#available-implementations[EmbeddingClient Implementations].
5340

54-
* Add the Qdrant Boot Starter dependency to your project:
41+
For example to use the xref:api/embeddings/openai-embeddings.adoc[OpenAI EmbeddingClient] add the following dependency to your project:
5542

5643
[source,xml]
5744
----
5845
<dependency>
5946
<groupId>org.springframework.ai</groupId>
60-
<artifactId>spring-ai-qdrant-store-spring-boot-starter</artifactId>
47+
<artifactId>spring-ai-openai-spring-boot-starter</artifactId>
6148
</dependency>
6249
----
6350

@@ -66,25 +53,37 @@ or to your Gradle `build.gradle` build file.
6653
[source,groovy]
6754
----
6855
dependencies {
69-
implementation 'org.springframework.ai:spring-ai-qdrant-store-spring-boot-starter'
56+
implementation 'org.springframework.ai:spring-ai-openai-spring-boot-starter'
7057
}
7158
----
7259

7360
TIP: Refer to the xref:getting-started.adoc#dependency-management[Dependency Management] section to add the Spring AI BOM to your build file.
61+
Refer to the xref:getting-started.adoc#repositories[Repositories] section to add Milestone and/or Snapshot Repositories to your build file.
62+
63+
To connect to Qdrant and use the `QdrantVectorStore`, you need to provide access details for your instance.
64+
A simple configuration can either be provided via Spring Boot's _application.properties_,
7465

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.
66+
[source,properties]
67+
----
68+
spring.ai.vectorstore.qdrant.host=<host of your qdrant instance>
69+
spring.ai.vectorstore.qdrant.port=<the GRPC port of your qdrant instance>
70+
spring.ai.vectorstore.qdrant.api-key=<your api key>
71+
spring.ai.vectorstore.qdrant.collection-name=<The name of the collection to use in Qdrant>
7672
77-
TIP: Refer to the xref:getting-started.adoc#repositories[Repositories] section to add Milestone and/or Snapshot Repositories to your build file.
73+
# API key if needed, e.g. OpenAI
74+
spring.ai.openai.api.key=<api-key>
75+
----
7876

77+
TIP: Check the list of xref:#qdrant-vectorstore-properties[configuration parameters] to learn about the default values and configuration options.
7978

8079
Now you can Auto-wire the Qdrant Vector Store in your application and use it
8180

8281
[source,java]
8382
----
84-
@Autowired
85-
VectorStore vectorStore;
83+
@Autowired VectorStore vectorStore;
84+
85+
// ...
8686
87-
...
8887
List <Document> documents = List.of(
8988
new Document("Spring AI rocks!! Spring AI rocks!! Spring AI rocks!! Spring AI rocks!! Spring AI rocks!!", Map.of("meta1", "meta1")),
9089
new Document("The World is Big and Salvation Lurks Around the Corner"),
@@ -97,24 +96,7 @@ vectorStore.add(List.of(document));
9796
List<Document> results = vectorStore.similaritySearch(SearchRequest.query("Spring").withTopK(5));
9897
----
9998

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
99+
=== Manual Configuration
118100

119101
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:
120102

@@ -162,7 +144,7 @@ public VectorStore vectorStore(QdrantVectorStoreConfig config, EmbeddingClient e
162144
}
163145
----
164146

165-
=== Metadata filtering
147+
== Metadata filtering
166148

167149
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.
168150

@@ -195,18 +177,18 @@ vectorStore.similaritySearch(SearchRequest.defaults()
195177

196178
NOTE: These filter expressions are converted into the equivalent Qdrant link:https://qdrant.tech/documentation/concepts/filtering/[filters].
197179

198-
199180
[[qdrant-vectorstore-properties]]
200-
== Qdrant VectorStore properties
181+
== Configuration properties
201182

202183
You can use the following properties in your Spring Boot configuration to customize the Qdrant vector store.
203184

185+
[cols="3,5,1"]
204186
|===
205187
|Property| Description | Default value
206188

207189
|`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
190+
|`spring.ai.vectorstore.qdrant.port`| The gRPC port of the Qdrant server. | 6334
209191
|`spring.ai.vectorstore.qdrant.api-key`| The API key to use for authentication with the Qdrant server. | -
210192
|`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
193+
|`spring.ai.vectorstore.qdrant.use-tls`| Whether to use TLS(HTTPS). | false
212194
|===

spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/vectorstore/qdrant/QdrantVectorStoreAutoConfiguration.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ public VectorStore vectorStore(EmbeddingClient embeddingClient, QdrantVectorStor
4343
.withCollectionName(properties.getCollectionName())
4444
.withHost(properties.getHost())
4545
.withPort(properties.getPort())
46-
.withTls(properties.useTls())
46+
.withTls(properties.isUseTls())
4747
.withApiKey(properties.getApiKey())
4848
.build();
4949

spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/vectorstore/qdrant/QdrantVectorStoreProperties.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ public void setPort(int port) {
7676
this.port = port;
7777
}
7878

79-
public boolean useTls() {
79+
public boolean isUseTls() {
8080
return this.useTls;
8181
}
8282

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/*
2+
* Copyright 2023-2023 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.junit.jupiter.api.Test;
20+
21+
import static org.assertj.core.api.Assertions.assertThat;
22+
23+
/**
24+
* @author Christian Tzolov
25+
*/
26+
public class PgVectorStorePropertiesTests {
27+
28+
@Test
29+
public void defaultValues() {
30+
var props = new QdrantVectorStoreProperties();
31+
32+
assertThat(props.getCollectionName()).isNull();
33+
assertThat(props.getHost()).isEqualTo("localhost");
34+
assertThat(props.getPort()).isEqualTo(6334);
35+
assertThat(props.isUseTls()).isFalse();
36+
assertThat(props.getApiKey()).isNull();
37+
}
38+
39+
@Test
40+
public void customValues() {
41+
var props = new QdrantVectorStoreProperties();
42+
43+
props.setCollectionName("MY_COLLECTION");
44+
props.setHost("MY_HOST");
45+
props.setPort(999);
46+
props.setUseTls(true);
47+
props.setApiKey("MY_API_KEY");
48+
49+
assertThat(props.getCollectionName()).isEqualTo("MY_COLLECTION");
50+
assertThat(props.getHost()).isEqualTo("MY_HOST");
51+
assertThat(props.getPort()).isEqualTo(999);
52+
assertThat(props.isUseTls()).isTrue();
53+
assertThat(props.getApiKey()).isEqualTo("MY_API_KEY");
54+
}
55+
56+
}

spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/vectorstore/qdrant/QdrantVectorStoreAutoConfigurationIT.java

Lines changed: 10 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,6 @@ public class QdrantVectorStoreAutoConfigurationIT {
5454

5555
private static final String COLLECTION_NAME = "test_collection";
5656

57-
private static final int EMBEDDING_DIMENSION = 384;
58-
5957
private static final int QDRANT_GRPC_PORT = 6334;
6058

6159
@Container
@@ -66,31 +64,6 @@ public class QdrantVectorStoreAutoConfigurationIT {
6664
new Document(getText("classpath:/test/data/time.shelter.txt")),
6765
new Document(getText("classpath:/test/data/great.depression.txt"), Map.of("depression", "bad")));
6866

69-
@BeforeAll
70-
static void setup() throws InterruptedException, ExecutionException {
71-
72-
String host = qdrantContainer.getHost();
73-
int port = qdrantContainer.getMappedPort(QDRANT_GRPC_PORT);
74-
QdrantClient client = new QdrantClient(QdrantGrpcClient.newBuilder(host, port, false).build());
75-
76-
client
77-
.createCollectionAsync(COLLECTION_NAME,
78-
VectorParams.newBuilder().setDistance(Distance.Cosine).setSize(EMBEDDING_DIMENSION).build())
79-
.get();
80-
81-
client.close();
82-
}
83-
84-
public static String getText(String uri) {
85-
var resource = new DefaultResourceLoader().getResource(uri);
86-
try {
87-
return resource.getContentAsString(StandardCharsets.UTF_8);
88-
}
89-
catch (IOException e) {
90-
throw new RuntimeException(e);
91-
}
92-
}
93-
9467
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
9568
.withConfiguration(AutoConfigurations.of(QdrantVectorStoreAutoConfiguration.class))
9669
.withUserConfiguration(Config.class)
@@ -121,6 +94,16 @@ public void addAndSearch() {
12194
});
12295
}
12396

97+
public static String getText(String uri) {
98+
var resource = new DefaultResourceLoader().getResource(uri);
99+
try {
100+
return resource.getContentAsString(StandardCharsets.UTF_8);
101+
}
102+
catch (IOException e) {
103+
throw new RuntimeException(e);
104+
}
105+
}
106+
124107
@Configuration(proxyBeanMethods = false)
125108
static class Config {
126109

0 commit comments

Comments
 (0)