fix: Guard empty input and validate id/embedding sizes in VespaEmbeddingStore.addAll (#5632)
## Issue <!-- 사람이 실제 이슈 번호로 갱신: 위 issues/ 초안을 등록한 뒤 그 번호를 적는다 --> Closes #5629 ## Change `VespaEmbeddingStore.addAll(ids, embeddings, embedded)` now returns early when `ids` or `embeddings` is null or empty, so an empty batch no longer opens a feed client or contacts the Vespa server. This matches the merged PgVector precedent (PR #4422) and the behaviour of other embedding stores (Milvus, Qdrant, etc.). The method also validates that `ids` and `embeddings` have the same size, alongside the existing `embedded` size check. This is a sibling-parity addition: today a mismatch surfaces only as `IndexOutOfBoundsException` when the 3-arg method is called directly, since the public `addAll(embeddings)` path builds matching ids internally. The new check fails fast with a clear `IllegalArgumentException` instead. The existing feed logic, exception messages, and formatting are unchanged. `isNullOrEmpty` was already imported, so no new dependencies or imports were added. ## General checklist - [X] There are no breaking changes (API, behaviour) - [X] I have added unit and/or integration tests for my change - [X] The tests cover both positive and negative cases - [ ] I have manually run all the unit and integration tests in the module I have added/changed, and they are all green <!-- Unit tests + spotless green; module ITs (VespaEmbeddingStoreIT/CloudIT) need a live Vespa server and were not run locally --> - [ ] I have manually run all the unit and integration tests in the [core](https://github.com/langchain4j/langchain4j/tree/main/langchain4j-core) and [main](https://github.com/langchain4j/langchain4j/tree/main/langchain4j) modules, and they are all green <!-- N/A — change is isolated to langchain4j-vespa --> - [ ] I have added/updated the [documentation](https://github.com/langchain4j/langchain4j/tree/main/docs/docs) <!-- N/A — no public API/behaviour doc change --> - [ ] I have added an example in the [examples repo](https://github.com/langchain4j/langchain4j-examples) (only for "big" features) <!-- N/A — small bug fix --> - [ ] I have added/updated [Spring Boot starter(s)](https://github.com/langchain4j/langchain4j-spring) (if applicable) <!-- N/A --> <!-- Checklist for adding new maven module: 생략 — 새 모듈 아님 --> <!-- Checklist for adding/changing embedding store integration: 생략 — 신규 통합 아님, 동작 변경은 데이터 영속 포맷과 무관(빈 입력 early-return + size 검증) -->
This commit is contained in:
parent
d225579243
commit
c289860d60
|
|
@ -170,6 +170,12 @@ public class VespaEmbeddingStore implements EmbeddingStore<TextSegment> {
|
|||
|
||||
@Override
|
||||
public void addAll(List<String> ids, List<Embedding> embeddings, List<TextSegment> embedded) {
|
||||
if (isNullOrEmpty(ids) || isNullOrEmpty(embeddings)) {
|
||||
return;
|
||||
}
|
||||
if (ids.size() != embeddings.size()) {
|
||||
throw new IllegalArgumentException("The list of ids and embeddings must have the same size");
|
||||
}
|
||||
if (embedded != null && embeddings.size() != embedded.size()) {
|
||||
throw new IllegalArgumentException("The list of embeddings and embedded must have the same size");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,14 @@
|
|||
package dev.langchain4j.store.embedding.vespa;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatCode;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
|
||||
import dev.langchain4j.data.embedding.Embedding;
|
||||
import java.lang.reflect.Field;
|
||||
import java.nio.file.Paths;
|
||||
import java.time.Duration;
|
||||
import java.util.List;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class VespaEmbeddingStoreTest {
|
||||
|
|
@ -82,6 +86,30 @@ class VespaEmbeddingStoreTest {
|
|||
assertThat(getFieldValue(store, "logResponses")).isEqualTo(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_throw_when_ids_and_embeddings_have_different_sizes() {
|
||||
// Given
|
||||
VespaEmbeddingStore store =
|
||||
VespaEmbeddingStore.builder().url("https://test.vespa.ai").build();
|
||||
Embedding embedding1 = Embedding.from(List.of(1f, 2f, 3f));
|
||||
Embedding embedding2 = Embedding.from(List.of(4f, 5f, 6f));
|
||||
|
||||
// When + Then
|
||||
assertThatThrownBy(() -> store.addAll(List.of("id1"), List.of(embedding1, embedding2), null))
|
||||
.isInstanceOf(IllegalArgumentException.class)
|
||||
.hasMessageContaining("same size");
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_not_throw_or_call_server_when_input_is_empty() {
|
||||
// Given
|
||||
VespaEmbeddingStore store =
|
||||
VespaEmbeddingStore.builder().url("https://test.vespa.ai").build();
|
||||
|
||||
// When + Then - empty input returns before any feeder/server interaction
|
||||
assertThatCode(() -> store.addAll(List.of(), List.of(), null)).doesNotThrowAnyException();
|
||||
}
|
||||
|
||||
private Object getFieldValue(Object object, String fieldName) throws Exception {
|
||||
Field field = object.getClass().getDeclaredField(fieldName);
|
||||
field.setAccessible(true);
|
||||
|
|
|
|||
Loading…
Reference in New Issue