Skip to content

Commit 48bcbd1

Browse files
sobychackomarkpollack
authored andcommitted
Add builder pattern to QdrantVectorStore
Introduces a builder pattern for configuring QdrantVectorStore instances to provide a more flexible and type-safe way to create and configure vector stores. This change: - Makes configuration more intuitive through fluent builder methods - Improves validation by enforcing required parameters at compile time - Deprecates old constructors in favor of the builder pattern - Adds comprehensive builder tests to ensure reliability - Updates reference documentation with builder usage examples - Maintains backward compatibility while providing a clear migration path The builder pattern simplifies QdrantVectorStore configuration by providing clear method names, proper validation, and better IDE support through method chaining. This makes the API more user-friendly and helps prevent configuration errors at compile time rather than runtime.
1 parent 19e61bf commit 48bcbd1

File tree

6 files changed

+395
-117
lines changed

6 files changed

+395
-117
lines changed

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

Lines changed: 95 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,26 @@
22

33
This section walks you through setting up the Qdrant `VectorStore` to store document embeddings and perform similarity searches.
44

5-
link:https://www.qdrant.tech/[Qdrant] is an open-source, high-performance vector search engine/database.
5+
link:https://www.qdrant.tech/[Qdrant] is an open-source, high-performance vector search engine/database. It uses HNSW (Hierarchical Navigable Small World) algorithm for efficient k-NN search operations and provides advanced filtering capabilities for metadata-based queries.
66

77
== Prerequisites
88

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[EmbeddingModel] to generate the embeddings stored by the `QdrantVectorStore`.
1111

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).
13-
1412
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.
1513
If the collection is not created, the `QdrantVectorStore` will attempt to create one using the `Cosine` similarity and the dimension of the configured `EmbeddingModel`.
1614

1715
== Auto-configuration
1816

19-
Then add the Qdrant boot starter dependency to your project:
17+
Spring AI provides Spring Boot auto-configuration for the Qdrant Vector Store.
18+
To enable it, add the following dependency to your project's Maven `pom.xml` file:
2019

2120
[source,xml]
2221
----
2322
<dependency>
24-
<groupId>org.springframework.ai</groupId>
25-
<artifactId>spring-ai-qdrant-store-spring-boot-starter</artifactId>
23+
<groupId>org.springframework.ai</groupId>
24+
<artifactId>spring-ai-qdrant-store-spring-boot-starter</artifactId>
2625
</dependency>
2726
----
2827

@@ -35,61 +34,27 @@ dependencies {
3534
}
3635
----
3736

38-
The vector store implementation can initialize the requisite schema for you, but you must opt-in by specifying the `initializeSchema` boolean in the appropriate constructor or by setting `...initialize-schema=true` in the `application.properties` file.
39-
40-
NOTE: this is a breaking change! In earlier versions of Spring AI, this schema initialization happened by default.
41-
42-
43-
The Vector Store, also requires an `EmbeddingModel` instance to calculate embeddings for the documents.
44-
You can pick one of the available xref:api/embeddings.adoc#available-implementations[EmbeddingModel Implementations].
45-
46-
For example to use the xref:api/embeddings/openai-embeddings.adoc[OpenAI EmbeddingModel] add the following dependency to your project:
47-
48-
[source,xml]
49-
----
50-
<dependency>
51-
<groupId>org.springframework.ai</groupId>
52-
<artifactId>spring-ai-openai-spring-boot-starter</artifactId>
53-
</dependency>
54-
----
55-
56-
or to your Gradle `build.gradle` build file.
57-
58-
[source,groovy]
59-
----
60-
dependencies {
61-
implementation 'org.springframework.ai:spring-ai-openai-spring-boot-starter'
62-
}
63-
----
64-
6537
TIP: Refer to the xref:getting-started.adoc#dependency-management[Dependency Management] section to add the Spring AI BOM to your build file.
66-
Refer to the xref:getting-started.adoc#repositories[Repositories] section to add Milestone and/or Snapshot Repositories to your build file.
6738

68-
To connect to Qdrant and use the `QdrantVectorStore`, you need to provide access details for your instance.
69-
A simple configuration can either be provided via Spring Boot's _application.properties_,
39+
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.
7040

71-
[source,properties]
72-
----
73-
spring.ai.vectorstore.qdrant.host=<host of your qdrant instance>
74-
spring.ai.vectorstore.qdrant.port=<the GRPC port of your qdrant instance>
75-
spring.ai.vectorstore.qdrant.api-key=<your api key>
76-
spring.ai.vectorstore.qdrant.collection-name=<The name of the collection to use in Qdrant>
41+
TIP: Refer to the xref:getting-started.adoc#repositories[Repositories] section to add Milestone and/or Snapshot Repositories to your build file.
7742

78-
# API key if needed, e.g. OpenAI
79-
spring.ai.openai.api.key=<api-key>
80-
----
43+
The vector store implementation can initialize the requisite schema for you, but you must opt-in by specifying the `initializeSchema` boolean in the builder or by setting `...initialize-schema=true` in the `application.properties` file.
44+
45+
NOTE: this is a breaking change! In earlier versions of Spring AI, this schema initialization happened by default.
8146

82-
TIP: Check the list of xref:#qdrant-vectorstore-properties[configuration parameters] to learn about the default values and configuration options.
47+
Additionally, you will need a configured `EmbeddingModel` bean. Refer to the xref:api/embeddings.adoc#available-implementations[EmbeddingModel] section for more information.
8348

84-
Now you can Auto-wire the Qdrant Vector Store in your application and use it
49+
Now you can auto-wire the `QdrantVectorStore` as a vector store in your application.
8550

8651
[source,java]
8752
----
8853
@Autowired VectorStore vectorStore;
8954
9055
// ...
9156
92-
List <Document> documents = List.of(
57+
List<Document> documents = List.of(
9358
new Document("Spring AI rocks!! Spring AI rocks!! Spring AI rocks!! Spring AI rocks!! Spring AI rocks!!", Map.of("meta1", "meta1")),
9459
new Document("The World is Big and Salvation Lurks Around the Corner"),
9560
new Document("You walk forward facing the past and you turn back toward the future.", Map.of("meta2", "meta2")));
@@ -98,62 +63,48 @@ List <Document> documents = List.of(
9863
vectorStore.add(documents);
9964
10065
// Retrieve documents similar to a query
101-
List<Document> results = this.vectorStore.similaritySearch(SearchRequest.query("Spring").withTopK(5));
66+
List<Document> results = vectorStore.similaritySearch(SearchRequest.query("Spring").withTopK(5));
10267
----
10368

10469
[[qdrant-vectorstore-properties]]
105-
=== Configuration properties
106-
107-
You can use the following properties in your Spring Boot configuration to customize the Qdrant vector store.
70+
=== Configuration Properties
10871

109-
[cols="3,5,1",stripes=even]
110-
|===
111-
|Property| Description | Default value
112-
113-
|`spring.ai.vectorstore.qdrant.host`| The host of the Qdrant server. | localhost
114-
|`spring.ai.vectorstore.qdrant.port`| The gRPC port of the Qdrant server. | 6334
115-
|`spring.ai.vectorstore.qdrant.api-key`| The API key to use for authentication with the Qdrant server. | -
116-
|`spring.ai.vectorstore.qdrant.collection-name`| The name of the collection to use in Qdrant. | -
117-
|`spring.ai.vectorstore.qdrant.use-tls`| Whether to use TLS(HTTPS). | false
118-
|`spring.ai.vectorstore.qdrant.initialize-schema`| Whether to initialize the backend schema or not | false
119-
|===
120-
121-
== Metadata filtering
122-
123-
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.
124-
125-
For example, you can use either the text expression language:
72+
To connect to Qdrant and use the `QdrantVectorStore`, you need to provide access details for your instance.
73+
A simple configuration can be provided via Spring Boot's `application.yml`:
12674

127-
[source,java]
75+
[source,yaml]
12876
----
129-
vectorStore.similaritySearch(
130-
SearchRequest.defaults()
131-
.withQuery("The World")
132-
.withTopK(TOP_K)
133-
.withSimilarityThreshold(SIMILARITY_THRESHOLD)
134-
.withFilterExpression("author in ['john', 'jill'] && article_type == 'blog'"));
77+
spring:
78+
ai:
79+
vectorstore:
80+
qdrant:
81+
host: <qdrant host>
82+
port: <qdrant grpc port>
83+
api-key: <qdrant api key>
84+
collection-name: <collection name>
85+
use-tls: false
86+
initialize-schema: true
87+
batching-strategy: TOKEN_COUNT # Optional: Controls how documents are batched for embedding
13588
----
13689

137-
or programmatically using the `Filter.Expression` DSL:
90+
Properties starting with `spring.ai.vectorstore.qdrant.*` are used to configure the `QdrantVectorStore`:
13891

139-
[source,java]
140-
----
141-
FilterExpressionBuilder b = new FilterExpressionBuilder();
142-
143-
vectorStore.similaritySearch(SearchRequest.defaults()
144-
.withQuery("The World")
145-
.withTopK(TOP_K)
146-
.withSimilarityThreshold(SIMILARITY_THRESHOLD)
147-
.withFilterExpression(b.and(
148-
b.in("author", "john", "jill"),
149-
b.eq("article_type", "blog")).build()));
150-
----
151-
152-
NOTE: These filter expressions are converted into the equivalent Qdrant link:https://qdrant.tech/documentation/concepts/filtering/[filters].
92+
[cols="2,5,1",stripes=even]
93+
|===
94+
|Property | Description | Default Value
95+
96+
|`spring.ai.vectorstore.qdrant.host`| The host of the Qdrant server | `localhost`
97+
|`spring.ai.vectorstore.qdrant.port`| The gRPC port of the Qdrant server | `6334`
98+
|`spring.ai.vectorstore.qdrant.api-key`| The API key to use for authentication | -
99+
|`spring.ai.vectorstore.qdrant.collection-name`| The name of the collection to use | `vector_store`
100+
|`spring.ai.vectorstore.qdrant.use-tls`| Whether to use TLS(HTTPS) | `false`
101+
|`spring.ai.vectorstore.qdrant.initialize-schema`| Whether to initialize the schema | `false`
102+
|`spring.ai.vectorstore.qdrant.batching-strategy`| Strategy for batching documents when calculating embeddings. Options are `TOKEN_COUNT` or `FIXED_SIZE` | `TOKEN_COUNT`
103+
|===
153104

154105
== Manual Configuration
155106

156-
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:
107+
Instead of using the Spring Boot auto-configuration, you can manually configure the Qdrant vector store. For this you need to add the `spring-ai-qdrant-store` to your project:
157108

158109
[source,xml]
159110
----
@@ -168,35 +119,79 @@ or to your Gradle `build.gradle` build file.
168119
[source,groovy]
169120
----
170121
dependencies {
171-
implementation 'org.springframework.ai:spring-ai-qdrant'
122+
implementation 'org.springframework.ai:spring-ai-qdrant-store'
172123
}
173124
----
174125

175-
To configure Qdrant in your application, you can create a QdrantClient:
126+
TIP: Refer to the xref:getting-started.adoc#dependency-management[Dependency Management] section to add the Spring AI BOM to your build file.
127+
128+
Create a Qdrant client bean:
176129

177130
[source,java]
178131
----
179132
@Bean
180133
public QdrantClient qdrantClient() {
181-
182134
QdrantGrpcClient.Builder grpcClientBuilder =
183135
QdrantGrpcClient.newBuilder(
184136
"<QDRANT_HOSTNAME>",
185137
<QDRANT_GRPC_PORT>,
186-
<IS_TSL>);
138+
<IS_TLS>);
187139
grpcClientBuilder.withApiKey("<QDRANT_API_KEY>");
188140
189141
return new QdrantClient(grpcClientBuilder.build());
190142
}
191143
----
192144

193-
Integrate with OpenAI's embeddings by adding the Spring Boot OpenAI starter to your project.
194-
This provides you with an implementation of the Embeddings client:
145+
Then create the `QdrantVectorStore` bean using the builder pattern:
195146

196147
[source,java]
197148
----
198149
@Bean
199-
public QdrantVectorStore vectorStore(EmbeddingModel embeddingModel, QdrantClient qdrantClient) {
200-
return new QdrantVectorStore(qdrantClient, "<QDRANT_COLLECTION_NAME>", embeddingModel);
150+
public VectorStore vectorStore(QdrantClient qdrantClient, EmbeddingModel embeddingModel) {
151+
return QdrantVectorStore.builder(qdrantClient)
152+
.embeddingModel(embeddingModel)
153+
.collectionName("custom-collection") // Optional: defaults to "vector_store"
154+
.initializeSchema(true) // Optional: defaults to false
155+
.batchingStrategy(new TokenCountBatchingStrategy()) // Optional: defaults to TokenCountBatchingStrategy
156+
.build();
201157
}
158+
159+
// This can be any EmbeddingModel implementation
160+
@Bean
161+
public EmbeddingModel embeddingModel() {
162+
return new OpenAiEmbeddingModel(new OpenAiApi(System.getenv("OPENAI_API_KEY")));
163+
}
164+
----
165+
166+
== Metadata Filtering
167+
168+
You can leverage the generic, portable xref:api/vectordbs.adoc#metadata-filters[metadata filters] with Qdrant store as well.
169+
170+
For example, you can use either the text expression language:
171+
172+
[source,java]
173+
----
174+
vectorStore.similaritySearch(
175+
SearchRequest.defaults()
176+
.withQuery("The World")
177+
.withTopK(TOP_K)
178+
.withSimilarityThreshold(SIMILARITY_THRESHOLD)
179+
.withFilterExpression("author in ['john', 'jill'] && article_type == 'blog'"));
180+
----
181+
182+
or programmatically using the `Filter.Expression` DSL:
183+
184+
[source,java]
202185
----
186+
FilterExpressionBuilder b = new FilterExpressionBuilder();
187+
188+
vectorStore.similaritySearch(SearchRequest.defaults()
189+
.withQuery("The World")
190+
.withTopK(TOP_K)
191+
.withSimilarityThreshold(SIMILARITY_THRESHOLD)
192+
.withFilterExpression(b.and(
193+
b.in("author", "john", "jill"),
194+
b.eq("article_type", "blog")).build()));
195+
----
196+
197+
NOTE: These (portable) filter expressions get automatically converted into the proprietary Qdrant link:https://qdrant.tech/documentation/concepts/filtering/[filter expressions].

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

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,9 +77,14 @@ public QdrantVectorStore vectorStore(EmbeddingModel embeddingModel, QdrantVector
7777
QdrantClient qdrantClient, ObjectProvider<ObservationRegistry> observationRegistry,
7878
ObjectProvider<VectorStoreObservationConvention> customObservationConvention,
7979
BatchingStrategy batchingStrategy) {
80-
return new QdrantVectorStore(qdrantClient, properties.getCollectionName(), embeddingModel,
81-
properties.isInitializeSchema(), observationRegistry.getIfUnique(() -> ObservationRegistry.NOOP),
82-
customObservationConvention.getIfAvailable(() -> null), batchingStrategy);
80+
return QdrantVectorStore.builder(qdrantClient)
81+
.collectionName(properties.getCollectionName())
82+
.embeddingModel(embeddingModel)
83+
.initializeSchema(properties.isInitializeSchema())
84+
.observationRegistry(observationRegistry.getIfUnique(() -> ObservationRegistry.NOOP))
85+
.customObservationConvention(customObservationConvention.getIfAvailable(() -> null))
86+
.batchingStrategy(batchingStrategy)
87+
.build();
8388
}
8489

8590
static class PropertiesQdrantConnectionDetails implements QdrantConnectionDetails {

0 commit comments

Comments
 (0)