Skip to content

Commit 6035516

Browse files
sobychackoilayaperumalg
authored andcommitted
GH-2165: Simplify VectorStore delete method to return void
- Change VectorStore.delete() and related implementations to return void instead of Optional<Boolean> - Remove unnecessary boolean return values and success status checks across all vector store implementations - Clean up tests by removing redundant assertions - Implementations continue using runtime exceptions for error signaling Signed-off-by: Soby Chacko <[email protected]>
1 parent b466159 commit 6035516

File tree

26 files changed

+43
-127
lines changed

26 files changed

+43
-127
lines changed

spring-ai-core/src/main/java/org/springframework/ai/vectorstore/SimpleVectorStore.java

+1-2
Original file line numberDiff line numberDiff line change
@@ -106,11 +106,10 @@ public void doAdd(List<Document> documents) {
106106
}
107107

108108
@Override
109-
public Optional<Boolean> doDelete(List<String> idList) {
109+
public void doDelete(List<String> idList) {
110110
for (String id : idList) {
111111
this.store.remove(id);
112112
}
113-
return Optional.of(true);
114113
}
115114

116115
@Override

spring-ai-core/src/main/java/org/springframework/ai/vectorstore/VectorStore.java

+1-3
Original file line numberDiff line numberDiff line change
@@ -59,10 +59,8 @@ default void accept(List<Document> documents) {
5959
/**
6060
* Deletes documents from the vector store.
6161
* @param idList list of document ids for which documents will be removed.
62-
* @return Returns true if the documents were successfully deleted.
6362
*/
64-
@Nullable
65-
Optional<Boolean> delete(List<String> idList);
63+
void delete(List<String> idList);
6664

6765
/**
6866
* Deletes documents from the vector store based on filter criteria.

spring-ai-core/src/main/java/org/springframework/ai/vectorstore/observation/AbstractObservationVectorStore.java

+3-5
Original file line numberDiff line numberDiff line change
@@ -87,14 +87,13 @@ public void add(List<Document> documents) {
8787
}
8888

8989
@Override
90-
@Nullable
91-
public Optional<Boolean> delete(List<String> deleteDocIds) {
90+
public void delete(List<String> deleteDocIds) {
9291

9392
VectorStoreObservationContext observationContext = this
9493
.createObservationContextBuilder(VectorStoreObservationContext.Operation.DELETE.value())
9594
.build();
9695

97-
return VectorStoreObservationDocumentation.AI_VECTOR_STORE
96+
VectorStoreObservationDocumentation.AI_VECTOR_STORE
9897
.observation(this.customObservationConvention, DEFAULT_OBSERVATION_CONVENTION, () -> observationContext,
9998
this.observationRegistry)
10099
.observe(() -> this.doDelete(deleteDocIds));
@@ -140,9 +139,8 @@ public List<Document> similaritySearch(SearchRequest request) {
140139
/**
141140
* Perform the actual delete operation.
142141
* @param idList the list of document IDs to delete
143-
* @return true if the documents were successfully deleted
144142
*/
145-
public abstract Optional<Boolean> doDelete(List<String> idList);
143+
public abstract void doDelete(List<String> idList);
146144

147145
/**
148146
* Template method for concrete implementations to provide filter-based deletion

spring-ai-core/src/test/java/org/springframework/ai/vectorstore/SimpleVectorStoreTests.java

+3-2
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838

3939
import static org.assertj.core.api.Assertions.assertThat;
4040
import static org.assertj.core.api.Assertions.assertThatThrownBy;
41+
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
4142
import static org.mockito.ArgumentMatchers.any;
4243
import static org.mockito.Mockito.mock;
4344
import static org.mockito.Mockito.when;
@@ -112,8 +113,8 @@ void shouldDeleteDocuments() {
112113
@Test
113114
void shouldHandleDeleteOfNonexistentDocument() {
114115
this.vectorStore.delete(List.of("nonexistent-id"));
115-
// Should not throw exception and return true
116-
assertThat(this.vectorStore.delete(List.of("nonexistent-id")).get()).isTrue();
116+
// Should not throw exception
117+
assertDoesNotThrow(() -> this.vectorStore.delete(List.of("nonexistent-id")));
117118
}
118119

119120
@Test

vector-stores/spring-ai-azure-cosmos-db-store/src/main/java/org/springframework/ai/vectorstore/cosmosdb/CosmosDBVectorStore.java

+1-4
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,7 @@ public void doAdd(List<Document> documents) {
271271
}
272272

273273
@Override
274-
public Optional<Boolean> doDelete(List<String> idList) {
274+
public void doDelete(List<String> idList) {
275275
try {
276276
// Convert the list of IDs into bulk delete operations
277277
List<CosmosItemOperation> itemOperations = idList.stream()
@@ -285,12 +285,9 @@ public Optional<Boolean> doDelete(List<String> idList) {
285285
response.getResponse().getStatusCode()))
286286
.doOnError(error -> logger.error("Error deleting document: {}", error.getMessage()))
287287
.blockLast(); // This will block until all operations have finished
288-
289-
return Optional.of(true);
290288
}
291289
catch (Exception e) {
292290
logger.error("Exception while deleting documents: {}", e.getMessage());
293-
return Optional.of(false);
294291
}
295292
}
296293

vector-stores/spring-ai-azure-store/src/main/java/org/springframework/ai/vectorstore/azure/AzureVectorStore.java

+2-16
Original file line numberDiff line numberDiff line change
@@ -188,31 +188,17 @@ public void doAdd(List<Document> documents) {
188188
}
189189

190190
@Override
191-
public Optional<Boolean> doDelete(List<String> documentIds) {
191+
public void doDelete(List<String> documentIds) {
192192

193193
Assert.notNull(documentIds, "The document ID list should not be null.");
194-
if (CollectionUtils.isEmpty(documentIds)) {
195-
return Optional.of(true); // nothing to do;
196-
}
197194

198195
final var searchDocumentIds = documentIds.stream().map(documentId -> {
199196
SearchDocument searchDocument = new SearchDocument();
200197
searchDocument.put(ID_FIELD_NAME, documentId);
201198
return searchDocument;
202199
}).toList();
203200

204-
var results = this.searchClient.deleteDocuments(searchDocumentIds);
205-
206-
boolean resSuccess = true;
207-
208-
for (IndexingResult result : results.getResults()) {
209-
if (!result.isSucceeded()) {
210-
resSuccess = false;
211-
break;
212-
}
213-
}
214-
215-
return Optional.of(resSuccess);
201+
this.searchClient.deleteDocuments(searchDocumentIds);
216202
}
217203

218204
@Override

vector-stores/spring-ai-cassandra-store/src/main/java/org/springframework/ai/vectorstore/cassandra/CassandraVectorStore.java

+2-9
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,7 @@ public void doAdd(List<Document> documents) {
305305
}
306306

307307
@Override
308-
public Optional<Boolean> doDelete(List<String> idList) {
308+
public void doDelete(List<String> idList) {
309309
CompletableFuture[] futures = new CompletableFuture[idList.size()];
310310
int i = 0;
311311
for (String id : idList) {
@@ -314,7 +314,6 @@ public Optional<Boolean> doDelete(List<String> idList) {
314314
futures[i++] = this.session.executeAsync(s).toCompletableFuture();
315315
}
316316
CompletableFuture.allOf(futures).join();
317-
return Optional.of(Boolean.TRUE);
318317
}
319318

320319
@Override
@@ -339,13 +338,7 @@ protected void doDelete(Filter.Expression filterExpression) {
339338
if (!matchingDocs.isEmpty()) {
340339
// Then delete those documents by ID
341340
List<String> idsToDelete = matchingDocs.stream().map(Document::getId).collect(Collectors.toList());
342-
343-
Optional<Boolean> result = delete(idsToDelete);
344-
345-
if (result.isPresent() && !result.get()) {
346-
throw new IllegalStateException("Failed to delete some documents");
347-
}
348-
341+
delete(idsToDelete);
349342
logger.debug("Deleted {} documents matching filter expression", idsToDelete.size());
350343
}
351344
}

vector-stores/spring-ai-chroma-store/src/main/java/org/springframework/ai/chroma/vectorstore/ChromaVectorStore.java

+2-3
Original file line numberDiff line numberDiff line change
@@ -158,10 +158,9 @@ public void doAdd(@NonNull List<Document> documents) {
158158
}
159159

160160
@Override
161-
public Optional<Boolean> doDelete(@NonNull List<String> idList) {
161+
public void doDelete(List<String> idList) {
162162
Assert.notNull(idList, "Document id list must not be null");
163-
int status = this.chromaApi.deleteEmbeddings(this.collectionId, new DeleteEmbeddingsRequest(idList));
164-
return Optional.of(status == 200);
163+
this.chromaApi.deleteEmbeddings(this.collectionId, new DeleteEmbeddingsRequest(idList));
165164
}
166165

167166
@Override

vector-stores/spring-ai-chroma-store/src/test/java/org/springframework/ai/chroma/vectorstore/ChromaVectorStoreIT.java

+2-3
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,7 @@ public void addAndSearch() {
8888
assertThat(resultDoc.getMetadata()).containsKeys("meta2", DocumentMetadata.DISTANCE.value());
8989

9090
// Remove all documents from the store
91-
assertThat(vectorStore.delete(this.documents.stream().map(doc -> doc.getId()).toList()))
92-
.isEqualTo(Optional.of(Boolean.TRUE));
91+
vectorStore.delete(this.documents.stream().map(doc -> doc.getId()).toList());
9392

9493
List<Document> results2 = vectorStore
9594
.similaritySearch(SearchRequest.builder().query("Great").topK(1).build());
@@ -118,7 +117,7 @@ public void simpleSearch() {
118117
assertThat(resultDoc.getText()).isEqualTo("The sky is blue because of Rayleigh scattering.");
119118

120119
// Remove all documents from the store
121-
assertThat(vectorStore.delete(List.of(document.getId()))).isEqualTo(Optional.of(Boolean.TRUE));
120+
vectorStore.delete(List.of(document.getId()));
122121

123122
results = vectorStore.similaritySearch(SearchRequest.builder().query("Why is the sky blue?").build());
124123
assertThat(results).hasSize(0);

vector-stores/spring-ai-coherence-store/src/main/java/org/springframework/ai/vectorstore/coherence/CoherenceVectorStore.java

+2-8
Original file line numberDiff line numberDiff line change
@@ -178,21 +178,15 @@ public void doAdd(final List<Document> documents) {
178178
}
179179

180180
@Override
181-
public Optional<Boolean> doDelete(final List<String> idList) {
181+
public void doDelete(final List<String> idList) {
182182
var chunkIds = idList.stream().map(this::toChunkId).toList();
183-
Map<DocumentChunk.Id, Boolean> results = this.documentChunks.invokeAll(chunkIds, entry -> {
183+
this.documentChunks.invokeAll(chunkIds, entry -> {
184184
if (entry.isPresent()) {
185185
entry.remove(false);
186186
return true;
187187
}
188188
return false;
189189
});
190-
for (boolean r : results.values()) {
191-
if (!r) {
192-
return Optional.of(false);
193-
}
194-
}
195-
return Optional.of(true);
196190
}
197191

198192
@Override

vector-stores/spring-ai-elasticsearch-store/src/main/java/org/springframework/ai/vectorstore/elasticsearch/ElasticsearchVectorStore.java

+1-2
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ public void doAdd(List<Document> documents) {
209209
}
210210

211211
@Override
212-
public Optional<Boolean> doDelete(List<String> idList) {
212+
public void doDelete(List<String> idList) {
213213
BulkRequest.Builder bulkRequestBuilder = new BulkRequest.Builder();
214214
// For the index to be present, either it must be pre-created or set the
215215
// initializeSchema to true.
@@ -219,7 +219,6 @@ public Optional<Boolean> doDelete(List<String> idList) {
219219
for (String id : idList) {
220220
bulkRequestBuilder.operations(op -> op.delete(idx -> idx.index(this.options.getIndexName()).id(id)));
221221
}
222-
return Optional.of(bulkRequest(bulkRequestBuilder.build()).errors());
223222
}
224223

225224
@Override

vector-stores/spring-ai-gemfire-store/src/main/java/org/springframework/ai/vectorstore/gemfire/GemFireVectorStore.java

+1-3
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,7 @@ public void doAdd(List<Document> documents) {
231231
}
232232

233233
@Override
234-
public Optional<Boolean> doDelete(List<String> idList) {
234+
public void doDelete(List<String> idList) {
235235
try {
236236
this.client.method(HttpMethod.DELETE)
237237
.uri("/" + this.indexName + EMBEDDINGS)
@@ -242,9 +242,7 @@ public Optional<Boolean> doDelete(List<String> idList) {
242242
}
243243
catch (Exception e) {
244244
logger.warn("Error removing embedding: {}", e.getMessage(), e);
245-
return Optional.of(false);
246245
}
247-
return Optional.of(true);
248246
}
249247

250248
@Override

vector-stores/spring-ai-hanadb-store/src/main/java/org/springframework/ai/vectorstore/hanadb/HanaCloudVectorStore.java

+1-2
Original file line numberDiff line numberDiff line change
@@ -126,10 +126,9 @@ public void doAdd(List<Document> documents) {
126126
}
127127

128128
@Override
129-
public Optional<Boolean> doDelete(List<String> idList) {
129+
public void doDelete(List<String> idList) {
130130
int deleteCount = this.repository.deleteEmbeddingsById(this.tableName, idList);
131131
logger.info("{} embeddings deleted", deleteCount);
132-
return Optional.of(deleteCount == idList.size());
133132
}
134133

135134
public int purgeEmbeddings() {

vector-stores/spring-ai-mariadb-store/src/main/java/org/springframework/ai/vectorstore/mariadb/MariaDBVectorStore.java

+1-3
Original file line numberDiff line numberDiff line change
@@ -318,15 +318,13 @@ private String toJson(Map<String, Object> map) {
318318
}
319319

320320
@Override
321-
public Optional<Boolean> doDelete(List<String> idList) {
321+
public void doDelete(List<String> idList) {
322322
int updateCount = 0;
323323
for (String id : idList) {
324324
int count = this.jdbcTemplate.update(
325325
String.format("DELETE FROM %s WHERE %s = ?", getFullyQualifiedTableName(), this.idFieldName), id);
326326
updateCount = updateCount + count;
327327
}
328-
329-
return Optional.of(updateCount == idList.size());
330328
}
331329

332330
@Override

vector-stores/spring-ai-milvus-store/src/main/java/org/springframework/ai/vectorstore/milvus/MilvusVectorStore.java

+1-3
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,7 @@ public void doAdd(List<Document> documents) {
274274
}
275275

276276
@Override
277-
public Optional<Boolean> doDelete(List<String> idList) {
277+
public void doDelete(List<String> idList) {
278278
Assert.notNull(idList, "Document id list must not be null");
279279

280280
String deleteExpression = String.format("%s in [%s]", this.idFieldName,
@@ -290,8 +290,6 @@ public Optional<Boolean> doDelete(List<String> idList) {
290290
if (deleteCount != idList.size()) {
291291
logger.warn(String.format("Deleted only %s entries from requested %s ", deleteCount, idList.size()));
292292
}
293-
294-
return Optional.of(status.getStatus() == Status.Success.getCode());
295293
}
296294

297295
@Override

vector-stores/spring-ai-mongodb-atlas-store/src/main/java/org/springframework/ai/vectorstore/mongodb/atlas/MongoDBAtlasVectorStore.java

+2-6
Original file line numberDiff line numberDiff line change
@@ -268,13 +268,9 @@ public void doAdd(List<Document> documents) {
268268
}
269269

270270
@Override
271-
public Optional<Boolean> doDelete(List<String> idList) {
271+
public void doDelete(List<String> idList) {
272272
Query query = new Query(org.springframework.data.mongodb.core.query.Criteria.where(ID_FIELD_NAME).in(idList));
273-
274-
var deleteRes = this.mongoTemplate.remove(query, this.collectionName);
275-
long deleteCount = deleteRes.getDeletedCount();
276-
277-
return Optional.of(deleteCount == idList.size());
273+
this.mongoTemplate.remove(query, this.collectionName);
278274
}
279275

280276
@Override

vector-stores/spring-ai-neo4j-store/src/main/java/org/springframework/ai/vectorstore/neo4j/Neo4jVectorStore.java

+2-3
Original file line numberDiff line numberDiff line change
@@ -221,20 +221,19 @@ public void doAdd(List<Document> documents) {
221221
}
222222

223223
@Override
224-
public Optional<Boolean> doDelete(List<String> idList) {
224+
public void doDelete(List<String> idList) {
225225

226226
try (var session = this.driver.session(this.sessionConfig)) {
227227

228228
// Those queries with internal, cypher based transaction management cannot be
229229
// run with executeWrite
230-
var summary = session
230+
session
231231
.run("""
232232
MATCH (n:%s) WHERE n.%s IN $ids
233233
CALL { WITH n DETACH DELETE n } IN TRANSACTIONS OF $transactionSize ROWS
234234
""".formatted(this.label, this.idProperty),
235235
Map.of("ids", idList, "transactionSize", DEFAULT_TRANSACTION_SIZE))
236236
.consume();
237-
return Optional.of(idList.size() == summary.counters().nodesDeleted());
238237
}
239238
}
240239

vector-stores/spring-ai-opensearch-store/src/main/java/org/springframework/ai/vectorstore/opensearch/OpenSearchVectorStore.java

+1-2
Original file line numberDiff line numberDiff line change
@@ -217,12 +217,11 @@ public void doAdd(List<Document> documents) {
217217
}
218218

219219
@Override
220-
public Optional<Boolean> doDelete(List<String> idList) {
220+
public void doDelete(List<String> idList) {
221221
BulkRequest.Builder bulkRequestBuilder = new BulkRequest.Builder();
222222
for (String id : idList) {
223223
bulkRequestBuilder.operations(op -> op.delete(idx -> idx.index(this.index).id(id)));
224224
}
225-
return Optional.of(bulkRequest(bulkRequestBuilder.build()).errors());
226225
}
227226

228227
private BulkResponse bulkRequest(BulkRequest bulkRequest) {

vector-stores/spring-ai-oracle-store/src/main/java/org/springframework/ai/vectorstore/oracle/OracleVectorStore.java

+1-5
Original file line numberDiff line numberDiff line change
@@ -286,7 +286,7 @@ private double[] normalize(final double[] v) {
286286
}
287287

288288
@Override
289-
public Optional<Boolean> doDelete(final List<String> idList) {
289+
public void doDelete(final List<String> idList) {
290290
final String sql = String.format("delete from %s where id=?", this.tableName);
291291
final int[] argTypes = { Types.VARCHAR };
292292

@@ -297,19 +297,15 @@ public Optional<Boolean> doDelete(final List<String> idList) {
297297

298298
final int[] deleteCounts = this.jdbcTemplate.batchUpdate(sql, batchArgs, argTypes);
299299

300-
int deleteCount = 0;
301300
for (int detailedResult : deleteCounts) {
302301
switch (detailedResult) {
303302
case Statement.EXECUTE_FAILED:
304303
break;
305304
case 1:
306305
case Statement.SUCCESS_NO_INFO:
307-
deleteCount++;
308306
break;
309307
}
310308
}
311-
312-
return Optional.of(deleteCount == idList.size());
313309
}
314310

315311
@Override

vector-stores/spring-ai-pgvector-store/src/main/java/org/springframework/ai/vectorstore/pgvector/PgVectorStore.java

+1-3
Original file line numberDiff line numberDiff line change
@@ -318,15 +318,13 @@ private Object convertIdToPgType(String id) {
318318
}
319319

320320
@Override
321-
public Optional<Boolean> doDelete(List<String> idList) {
321+
public void doDelete(List<String> idList) {
322322
int updateCount = 0;
323323
for (String id : idList) {
324324
int count = this.jdbcTemplate.update("DELETE FROM " + getFullyQualifiedTableName() + " WHERE id = ?",
325325
UUID.fromString(id));
326326
updateCount = updateCount + count;
327327
}
328-
329-
return Optional.of(updateCount == idList.size());
330328
}
331329

332330
@Override

0 commit comments

Comments
 (0)