Skip to content

Commit 24de06e

Browse files
dev-jonghoonparksobychacko
authored andcommitted
GH-3535: Make the content field configurable in Weaviate vector store properties
Fixes: #3535 Signed-off-by: jonghoonpark <dev@jonghoonpark.com>
1 parent 0d8eebd commit 24de06e

File tree

9 files changed

+308
-30
lines changed

9 files changed

+308
-30
lines changed

auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-weaviate/src/main/java/org/springframework/ai/vectorstore/weaviate/autoconfigure/WeaviateVectorStoreAutoConfiguration.java

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,14 @@
2828
import org.springframework.ai.vectorstore.SpringAIVectorStoreTypes;
2929
import org.springframework.ai.vectorstore.observation.VectorStoreObservationConvention;
3030
import org.springframework.ai.vectorstore.weaviate.WeaviateVectorStore;
31+
import org.springframework.ai.vectorstore.weaviate.WeaviateVectorStoreOptions;
3132
import org.springframework.beans.factory.ObjectProvider;
3233
import org.springframework.boot.autoconfigure.AutoConfiguration;
3334
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
3435
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
3536
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
3637
import org.springframework.boot.context.properties.EnableConfigurationProperties;
38+
import org.springframework.boot.context.properties.PropertyMapper;
3739
import org.springframework.context.annotation.Bean;
3840

3941
/**
@@ -42,6 +44,7 @@
4244
* @author Christian Tzolov
4345
* @author Eddú Meléndez
4446
* @author Soby Chacko
47+
* @author Jonghoon Park
4548
*/
4649
@AutoConfiguration
4750
@ConditionalOnClass({ EmbeddingModel.class, WeaviateVectorStore.class })
@@ -82,9 +85,8 @@ public WeaviateVectorStore vectorStore(EmbeddingModel embeddingModel, WeaviateCl
8285
WeaviateVectorStoreProperties properties, ObjectProvider<ObservationRegistry> observationRegistry,
8386
ObjectProvider<VectorStoreObservationConvention> customObservationConvention,
8487
BatchingStrategy batchingStrategy) {
85-
8688
return WeaviateVectorStore.builder(weaviateClient, embeddingModel)
87-
.objectClass(properties.getObjectClass())
89+
.options(mappingPropertiesToOptions(properties))
8890
.filterMetadataFields(properties.getFilterField()
8991
.entrySet()
9092
.stream()
@@ -97,6 +99,16 @@ public WeaviateVectorStore vectorStore(EmbeddingModel embeddingModel, WeaviateCl
9799
.build();
98100
}
99101

102+
WeaviateVectorStoreOptions mappingPropertiesToOptions(WeaviateVectorStoreProperties properties) {
103+
WeaviateVectorStoreOptions weaviateVectorStoreOptions = new WeaviateVectorStoreOptions();
104+
105+
PropertyMapper mapper = PropertyMapper.get();
106+
mapper.from(properties::getContentFieldName).whenHasText().to(weaviateVectorStoreOptions::setContentFieldName);
107+
mapper.from(properties::getObjectClass).whenHasText().to(weaviateVectorStoreOptions::setObjectClass);
108+
109+
return weaviateVectorStoreOptions;
110+
}
111+
100112
static class PropertiesWeaviateConnectionDetails implements WeaviateConnectionDetails {
101113

102114
private final WeaviateVectorStoreProperties properties;

auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-weaviate/src/main/java/org/springframework/ai/vectorstore/weaviate/autoconfigure/WeaviateVectorStoreProperties.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
* Configuration properties for Weaviate Vector Store.
2828
*
2929
* @author Christian Tzolov
30+
* @author Jonghoon Park
3031
*/
3132
@ConfigurationProperties(WeaviateVectorStoreProperties.CONFIG_PREFIX)
3233
public class WeaviateVectorStoreProperties {
@@ -41,6 +42,8 @@ public class WeaviateVectorStoreProperties {
4142

4243
private String objectClass = "SpringAiWeaviate";
4344

45+
private String contentFieldName = "content";
46+
4447
private ConsistentLevel consistencyLevel = WeaviateVectorStore.ConsistentLevel.ONE;
4548

4649
/**
@@ -78,6 +81,20 @@ public String getObjectClass() {
7881
return this.objectClass;
7982
}
8083

84+
/**
85+
* @since 1.1.0
86+
*/
87+
public String getContentFieldName() {
88+
return contentFieldName;
89+
}
90+
91+
/**
92+
* @since 1.1.0
93+
*/
94+
public void setContentFieldName(String contentFieldName) {
95+
this.contentFieldName = contentFieldName;
96+
}
97+
8198
public void setObjectClass(String indexName) {
8299
this.objectClass = indexName;
83100
}

auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-weaviate/src/test/java/org/springframework/ai/vectorstore/weaviate/autoconfigure/WeaviateVectorStoreAutoConfigurationIT.java

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2023-2024 the original author or authors.
2+
* Copyright 2023-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -35,6 +35,7 @@
3535
import org.springframework.ai.vectorstore.observation.VectorStoreObservationContext;
3636
import org.springframework.ai.vectorstore.weaviate.WeaviateVectorStore;
3737
import org.springframework.ai.vectorstore.weaviate.WeaviateVectorStore.MetadataField;
38+
import org.springframework.ai.vectorstore.weaviate.WeaviateVectorStoreOptions;
3839
import org.springframework.boot.autoconfigure.AutoConfigurations;
3940
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
4041
import org.springframework.context.annotation.Bean;
@@ -48,6 +49,7 @@
4849
* @author Eddú Meléndez
4950
* @author Soby Chacko
5051
* @author Thomas Vitale
52+
* @author Jonghoon Park
5153
*/
5254
@Testcontainers
5355
public class WeaviateVectorStoreAutoConfigurationIT {
@@ -174,6 +176,22 @@ public void autoConfigurationEnabledWhenTypeIsWeaviate() {
174176
});
175177
}
176178

179+
@Test
180+
public void testMappingPropertiesToOptions() {
181+
this.contextRunner
182+
.withPropertyValues("spring.ai.vectorstore.weaviate.object-class=CustomObjectClass",
183+
"spring.ai.vectorstore.weaviate.content-field-name=customContentFieldName")
184+
.run(context -> {
185+
WeaviateVectorStoreAutoConfiguration autoConfiguration = context
186+
.getBean(WeaviateVectorStoreAutoConfiguration.class);
187+
WeaviateVectorStoreProperties properties = context.getBean(WeaviateVectorStoreProperties.class);
188+
WeaviateVectorStoreOptions options = autoConfiguration.mappingPropertiesToOptions(properties);
189+
190+
assertThat(options.getObjectClass()).isEqualTo("CustomObjectClass");
191+
assertThat(options.getContentFieldName()).isEqualTo("customContentFieldName");
192+
});
193+
}
194+
177195
@Configuration(proxyBeanMethods = false)
178196
static class Config {
179197

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

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ public WeaviateClient weaviateClient() {
156156
@Bean
157157
public VectorStore vectorStore(WeaviateClient weaviateClient, EmbeddingModel embeddingModel) {
158158
return WeaviateVectorStore.builder(weaviateClient, embeddingModel)
159-
.objectClass("CustomClass") // Optional: defaults to "SpringAiWeaviate"
159+
.options(options) // Optional: use custom options
160160
.consistencyLevel(ConsistentLevel.QUORUM) // Optional: defaults to ConsistentLevel.ONE
161161
.filterMetadataFields(List.of( // Optional: fields that can be used in filters
162162
MetadataField.text("country"),
@@ -261,11 +261,14 @@ You can use the following properties in your Spring Boot configuration to custom
261261
|`spring.ai.vectorstore.weaviate.host`|The host of the Weaviate server|localhost:8080
262262
|`spring.ai.vectorstore.weaviate.scheme`|Connection schema|http
263263
|`spring.ai.vectorstore.weaviate.api-key`|The API key for authentication|
264-
|`spring.ai.vectorstore.weaviate.object-class`|The class name for storing documents|SpringAiWeaviate
264+
|`spring.ai.vectorstore.weaviate.object-class`|The class name for storing documents. should|SpringAiWeaviate
265+
|`spring.ai.vectorstore.weaviate.content-field-name`|The field name for content|content
265266
|`spring.ai.vectorstore.weaviate.consistency-level`|Desired tradeoff between consistency and speed|ConsistentLevel.ONE
266267
|`spring.ai.vectorstore.weaviate.filter-field`|Configures metadata fields that can be used in filters. Format: spring.ai.vectorstore.weaviate.filter-field.<field-name>=<field-type>|
267268
|===
268269

270+
TIP: Object class names should start with an uppercase letter, and field names should start with a lowercase letter. see link:https://weaviate.io/developers/weaviate/concepts/data#data-object-concepts[data-object-concepts]
271+
269272
== Accessing the Native Client
270273

271274
The Weaviate Vector Store implementation provides access to the underlying native Weaviate client (`WeaviateClient`) through the `getNativeClient()` method:

vector-stores/spring-ai-weaviate-store/src/main/java/org/springframework/ai/vectorstore/weaviate/WeaviateVectorStore.java

Lines changed: 32 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@
7575
* <pre>{@code
7676
* // Create the vector store with builder
7777
* WeaviateVectorStore vectorStore = WeaviateVectorStore.builder(weaviateClient, embeddingModel)
78-
* .objectClass("CustomClass") // Optional: Custom class name (default: SpringAiWeaviate)
78+
* .options(options) // Optional: use custom options
7979
* .consistencyLevel(ConsistentLevel.QUORUM) // Optional: Set consistency level (default: ONE)
8080
* .filterMetadataFields(List.of( // Optional: Configure filterable metadata fields
8181
* MetadataField.text("country"),
@@ -89,6 +89,7 @@
8989
* @author Josh Long
9090
* @author Soby Chacko
9191
* @author Thomas Vitale
92+
* @author Jonghoon Park
9293
* @since 1.0.0
9394
*/
9495
public class WeaviateVectorStore extends AbstractObservationVectorStore {
@@ -97,8 +98,6 @@ public class WeaviateVectorStore extends AbstractObservationVectorStore {
9798

9899
private static final String METADATA_FIELD_PREFIX = "meta_";
99100

100-
private static final String CONTENT_FIELD_NAME = "content";
101-
102101
private static final String METADATA_FIELD_NAME = "metadata";
103102

104103
private static final String ADDITIONAL_FIELD_NAME = "_additional";
@@ -111,9 +110,9 @@ public class WeaviateVectorStore extends AbstractObservationVectorStore {
111110

112111
private final WeaviateClient weaviateClient;
113112

114-
private final ConsistentLevel consistencyLevel;
113+
private final WeaviateVectorStoreOptions options;
115114

116-
private final String weaviateObjectClass;
115+
private final ConsistentLevel consistencyLevel;
117116

118117
/**
119118
* List of metadata fields (as field name and type) that can be used in similarity
@@ -157,9 +156,10 @@ protected WeaviateVectorStore(Builder builder) {
157156

158157
Assert.notNull(builder.weaviateClient, "WeaviateClient must not be null");
159158

159+
this.options = builder.options;
160+
160161
this.weaviateClient = builder.weaviateClient;
161162
this.consistencyLevel = builder.consistencyLevel;
162-
this.weaviateObjectClass = builder.weaviateObjectClass;
163163
this.filterMetadataFields = builder.filterMetadataFields;
164164
this.filterExpressionConverter = new WeaviateFilterExpressionConverter(
165165
this.filterMetadataFields.stream().map(MetadataField::name).toList());
@@ -179,7 +179,7 @@ private Field[] buildWeaviateSimilaritySearchFields() {
179179

180180
List<Field> searchWeaviateFieldList = new ArrayList<>();
181181

182-
searchWeaviateFieldList.add(Field.builder().name(CONTENT_FIELD_NAME).build());
182+
searchWeaviateFieldList.add(Field.builder().name(this.options.getContentFieldName()).build());
183183
searchWeaviateFieldList.add(Field.builder().name(METADATA_FIELD_NAME).build());
184184
searchWeaviateFieldList.addAll(this.filterMetadataFields.stream()
185185
.map(mf -> Field.builder().name(METADATA_FIELD_PREFIX + mf.name()).build())
@@ -247,7 +247,7 @@ private WeaviateObject toWeaviateObject(Document document, List<Document> docume
247247

248248
// https://weaviate.io/developers/weaviate/config-refs/datatypes
249249
Map<String, Object> fields = new HashMap<>();
250-
fields.put(CONTENT_FIELD_NAME, document.getText());
250+
fields.put(this.options.getContentFieldName(), document.getText());
251251
try {
252252
String metadataString = this.objectMapper.writeValueAsString(document.getMetadata());
253253
fields.put(METADATA_FIELD_NAME, metadataString);
@@ -265,7 +265,7 @@ private WeaviateObject toWeaviateObject(Document document, List<Document> docume
265265
}
266266

267267
return WeaviateObject.builder()
268-
.className(this.weaviateObjectClass)
268+
.className(this.options.getObjectClass())
269269
.id(document.getId())
270270
.vector(EmbeddingUtils.toFloatArray(embeddings.get(documents.indexOf(document))))
271271
.properties(fields)
@@ -277,7 +277,7 @@ public void doDelete(List<String> documentIds) {
277277

278278
Result<BatchDeleteResponse> result = this.weaviateClient.batch()
279279
.objectsBatchDeleter()
280-
.withClassName(this.weaviateObjectClass)
280+
.withClassName(this.options.getObjectClass())
281281
.withConsistencyLevel(this.consistencyLevel.name())
282282
.withWhere(WhereFilter.builder()
283283
.path("id")
@@ -336,7 +336,7 @@ public List<Document> doSimilaritySearch(SearchRequest request) {
336336

337337
GetBuilder.GetBuilderBuilder builder = GetBuilder.builder();
338338

339-
GetBuilderBuilder queryBuilder = builder.className(this.weaviateObjectClass)
339+
GetBuilderBuilder queryBuilder = builder.className(this.options.getObjectClass())
340340
.withNearVectorFilter(NearVectorArgument.builder()
341341
.vector(EmbeddingUtils.toFloatArray(embedding))
342342
.certainty((float) request.getSimilarityThreshold())
@@ -418,7 +418,7 @@ private Document toDocument(Map<String, ?> item) {
418418
}
419419

420420
// Content
421-
String content = (String) item.get(CONTENT_FIELD_NAME);
421+
String content = (String) item.get(this.options.getContentFieldName());
422422

423423
// @formatter:off
424424
return Document.builder()
@@ -434,7 +434,7 @@ public VectorStoreObservationContext.Builder createObservationContextBuilder(Str
434434

435435
return VectorStoreObservationContext.builder(VectorStoreProvider.WEAVIATE.value(), operationName)
436436
.dimensions(this.embeddingModel.dimensions())
437-
.collectionName(this.weaviateObjectClass);
437+
.collectionName(this.options.getObjectClass());
438438
}
439439

440440
@Override
@@ -526,7 +526,7 @@ public enum Type {
526526

527527
public static class Builder extends AbstractVectorStoreBuilder<Builder> {
528528

529-
private String weaviateObjectClass = "SpringAiWeaviate";
529+
private WeaviateVectorStoreOptions options = new WeaviateVectorStoreOptions();
530530

531531
private ConsistentLevel consistencyLevel = ConsistentLevel.ONE;
532532

@@ -552,10 +552,27 @@ private Builder(WeaviateClient weaviateClient, EmbeddingModel embeddingModel) {
552552
* @param objectClass the object class to use
553553
* @return this builder instance
554554
* @throws IllegalArgumentException if objectClass is null or empty
555+
* @deprecated Use
556+
* {@link org.springframework.ai.vectorstore.weaviate.WeaviateVectorStore.Builder#options(WeaviateVectorStoreOptions)}
557+
* instead.
555558
*/
559+
@Deprecated
556560
public Builder objectClass(String objectClass) {
557561
Assert.hasText(objectClass, "objectClass must not be empty");
558-
this.weaviateObjectClass = objectClass;
562+
this.options.setObjectClass(objectClass);
563+
return this;
564+
}
565+
566+
/**
567+
* Configures the Weaviate vector store option.
568+
* @param options the vector store options to use
569+
* @return this builder instance
570+
* @throws IllegalArgumentException if options is null or empty
571+
* @since 1.1.0
572+
*/
573+
public Builder options(WeaviateVectorStoreOptions options) {
574+
Assert.notNull(options, "options must not be empty");
575+
this.options = options;
559576
return this;
560577
}
561578

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/*
2+
* Copyright 2023-2025 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.vectorstore.weaviate;
18+
19+
import org.springframework.util.Assert;
20+
21+
/**
22+
* Provided Weaviate vector option configuration.
23+
*
24+
* @author Jonghoon Park
25+
* @since 1.1.0.
26+
*/
27+
public class WeaviateVectorStoreOptions {
28+
29+
private String objectClass = "SpringAiWeaviate";
30+
31+
private String contentFieldName = "content";
32+
33+
public String getObjectClass() {
34+
return objectClass;
35+
}
36+
37+
public void setObjectClass(String objectClass) {
38+
Assert.hasText(objectClass, "objectClass cannot be null or empty");
39+
this.objectClass = objectClass;
40+
}
41+
42+
public String getContentFieldName() {
43+
return contentFieldName;
44+
}
45+
46+
public void setContentFieldName(String contentFieldName) {
47+
Assert.hasText(contentFieldName, "contentFieldName cannot be null or empty");
48+
this.contentFieldName = contentFieldName;
49+
}
50+
51+
}

0 commit comments

Comments
 (0)