Skip to content

Commit f952fad

Browse files
authored
Add integration test for deleting vectors (#48)
## Problem The sdk currently lacks integration tests for deleting vectors. ## Solution Vectors can be deleted in multiple ways, so added an integration tests that covers all of the different possibilities. ## Type of Change - [ ] Bug fix (non-breaking change which fixes an issue) - [ ] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) - [ ] This change requires a documentation update - [ ] Infrastructure change (CI configs, etc) - [ ] Non-code change (docs, etc) - [X] None of the above: Integration tests ## Test Plan Ran integration tests
1 parent d1546e1 commit f952fad

File tree

3 files changed

+317
-17
lines changed

3 files changed

+317
-17
lines changed

src/integration/java/io/pinecone/helpers/BuildUpsertRequest.java

Lines changed: 63 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,23 +9,29 @@
99

1010
import java.util.ArrayList;
1111
import java.util.Arrays;
12+
import java.util.HashMap;
1213
import java.util.List;
1314

1415
public class BuildUpsertRequest {
1516
private static final float[][] upsertData = {{1.0F, 2.0F, 3.0F}, {4.0F, 5.0F, 6.0F}, {7.0F, 8.0F, 9.0F}};
16-
17+
public static final String[] metadataFields = new String[]{"genre", "year"};
1718
public static UpsertRequest buildRequiredUpsertRequest() {
18-
String namespace = RandomStringBuilder.build("ns", 8);
19-
List<String> upsertIds = Arrays.asList("v1", "v2", "v3");
20-
List<Vector> upsertVectors = new ArrayList<>();
19+
return buildRequiredUpsertRequest(new ArrayList<>(), "");
20+
}
21+
22+
public static UpsertRequest buildRequiredUpsertRequest(String namespace) {
23+
return buildRequiredUpsertRequest(new ArrayList<>(), namespace);
24+
}
2125

26+
public static UpsertRequest buildRequiredUpsertRequest(List<String> upsertIds, String namespace) {
27+
if (upsertIds.isEmpty()) upsertIds = Arrays.asList("v1", "v2", "v3");
28+
if (namespace.isEmpty()) namespace = RandomStringBuilder.build("ns", 8);
29+
30+
List<Vector> upsertVectors = new ArrayList<>();
2231
for (int i = 0; i < upsertData.length; i++) {
2332
upsertVectors.add(Vector.newBuilder()
2433
.addAllValues(Floats.asList(upsertData[i]))
25-
.setMetadata(Struct.newBuilder()
26-
.putFields("some_field", Value.newBuilder().setNumberValue(i).build())
27-
.build())
28-
.setId(upsertIds.get(i))
34+
.setId(upsertIds.get(i % upsertData.length))
2935
.build());
3036
}
3137

@@ -36,19 +42,46 @@ public static UpsertRequest buildRequiredUpsertRequest() {
3642
}
3743

3844
public static UpsertRequest buildOptionalUpsertRequest() {
39-
String namespace = RandomStringBuilder.build("ns", 8);
40-
List<String> hybridsIds = Arrays.asList("v4", "v5", "v6");
45+
return buildOptionalUpsertRequest(new ArrayList<>(), "");
46+
}
47+
48+
public static UpsertRequest buildOptionalUpsertRequest(String namespace) {
49+
return buildOptionalUpsertRequest(new ArrayList<>(), namespace);
50+
}
51+
52+
public static UpsertRequest buildOptionalUpsertRequest(List<String> upsertIds, String namespace) {
53+
return buildOptionalUpsertRequest(upsertIds, namespace, new HashMap<>());
54+
}
55+
56+
public static UpsertRequest buildOptionalUpsertRequest(List<String> upsertIds, String namespace, HashMap<String, List<String>> metadataMap) {
57+
if(upsertIds.isEmpty()) upsertIds = Arrays.asList("v4", "v5", "v6");
58+
if(namespace.isEmpty()) namespace = RandomStringBuilder.build("ns", 8);
59+
if(metadataMap.isEmpty()) metadataMap = createAndGetMetadataMap();
60+
4161
List<Vector> hybridVectors = new ArrayList<>();
4262
List<Integer> sparseIndices = Arrays.asList(0, 1, 2);
4363
List<Float> sparseValues = Arrays.asList(0.11f, 0.22f, 0.33f);
44-
for (int i = 0; i < hybridsIds.size(); i++) {
64+
65+
for (int i = 0; i < upsertIds.size(); i++) {
66+
String field1 = metadataFields[i % metadataFields.length];
67+
String field2 = metadataFields[(i+1) % metadataFields.length];
68+
int metadataValuesLength = metadataMap.get(field1).size();
69+
4570
hybridVectors.add(
4671
Vector.newBuilder()
4772
.addAllValues(Floats.asList(upsertData[i]))
73+
.setMetadata(Struct.newBuilder()
74+
.putFields(field1, Value.newBuilder().setStringValue(metadataMap.get(field1).get(i % metadataValuesLength)).build())
75+
.putFields(field2, Value.newBuilder().setStringValue(metadataMap.get(field2).get(i % metadataValuesLength)).build())
76+
.build())
4877
.setSparseValues(
49-
SparseValues.newBuilder().addAllIndices(sparseIndices).addAllValues(sparseValues).build()
78+
SparseValues
79+
.newBuilder()
80+
.addAllIndices(sparseIndices)
81+
.addAllValues(sparseValues)
82+
.build()
5083
)
51-
.setId(hybridsIds.get(i))
84+
.setId(upsertIds.get(i))
5285
.build());
5386
}
5487

@@ -57,4 +90,21 @@ public static UpsertRequest buildOptionalUpsertRequest() {
5790
.setNamespace(namespace)
5891
.build();
5992
}
93+
94+
public static HashMap<String, List<String>> createAndGetMetadataMap() {
95+
HashMap<String, List<String>> metadataMap;
96+
metadataMap = new HashMap<>();
97+
List<String> metadataValues1 = new ArrayList<>();
98+
metadataValues1.add("drama");
99+
metadataValues1.add("thriller");
100+
metadataValues1.add("fiction");
101+
metadataMap.put(metadataFields[0], metadataValues1);
102+
List<String> metadataValues2 = new ArrayList<>();
103+
metadataValues2.add("2019");
104+
metadataValues2.add("2020");
105+
metadataValues2.add("2021");
106+
metadataMap.put(metadataFields[1], metadataValues2);
107+
108+
return metadataMap;
109+
}
60110
}
Lines changed: 250 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,250 @@
1+
package io.pinecone.integration.dataplane;
2+
3+
import com.google.protobuf.Struct;
4+
import com.google.protobuf.Value;
5+
import io.pinecone.PineconeConnection;
6+
import io.pinecone.helpers.IndexManager;
7+
import io.pinecone.helpers.RandomStringBuilder;
8+
import io.pinecone.proto.*;
9+
import org.junit.jupiter.api.BeforeAll;
10+
import org.junit.jupiter.api.Test;
11+
12+
import java.io.IOException;
13+
import java.util.Arrays;
14+
import java.util.List;
15+
import java.util.concurrent.ExecutionException;
16+
17+
import static io.pinecone.helpers.BuildUpsertRequest.*;
18+
import static org.junit.jupiter.api.Assertions.assertEquals;
19+
import static org.junit.jupiter.api.Assertions.assertThrows;
20+
21+
public class UpsertAndDeleteTest {
22+
private static VectorServiceGrpc.VectorServiceBlockingStub blockingStub;
23+
private static VectorServiceGrpc.VectorServiceFutureStub futureStub;
24+
private static final int dimension = 3;
25+
26+
@BeforeAll
27+
public static void setUp() throws IOException, InterruptedException {
28+
PineconeConnection connection = new IndexManager().createIndexIfNotExists(dimension);
29+
blockingStub = connection.getBlockingStub();
30+
futureStub = connection.getFutureStub();
31+
}
32+
33+
@Test
34+
public void UpsertVectorsAndDeleteByIdSyncTest() throws InterruptedException {
35+
// Upsert vectors with required parameters
36+
String namespace = RandomStringBuilder.build("ns", 8);
37+
List<String> upsertIds = Arrays.asList("v1", "v2", "v3");
38+
UpsertResponse upsertResponse = blockingStub.upsert(buildRequiredUpsertRequest(upsertIds, namespace));
39+
Thread.sleep(3500);
40+
41+
// Get vector count before deleting vectors
42+
DescribeIndexStatsRequest describeIndexRequest = DescribeIndexStatsRequest.newBuilder().build();
43+
DescribeIndexStatsResponse describeIndexStatsResponse = blockingStub.describeIndexStats(describeIndexRequest);
44+
int startVectorCount = describeIndexStatsResponse.getNamespacesMap().get(namespace).getVectorCount();
45+
assertEquals(startVectorCount, upsertResponse.getUpsertedCount());
46+
47+
// Delete 1 vector
48+
String[] idsToDelete = new String[]{upsertIds.get(0)};
49+
DeleteRequest deleteRequest = DeleteRequest.newBuilder()
50+
.setNamespace(namespace)
51+
.addAllIds(Arrays.asList(idsToDelete))
52+
.setDeleteAll(false)
53+
.build();
54+
blockingStub.delete(deleteRequest);
55+
Thread.sleep(3500);
56+
57+
// Call describeIndexStats to get updated counts
58+
describeIndexStatsResponse = blockingStub.describeIndexStats(describeIndexRequest);
59+
// Verify updated vector count
60+
assertEquals(describeIndexStatsResponse.getNamespacesMap().get(namespace).getVectorCount(), startVectorCount - idsToDelete.length);
61+
startVectorCount -= idsToDelete.length;
62+
63+
// Delete multiple vectors
64+
idsToDelete = new String[]{upsertIds.get(1), upsertIds.get(2)};
65+
deleteRequest = DeleteRequest.newBuilder()
66+
.setNamespace(namespace)
67+
.addAllIds(Arrays.asList(idsToDelete))
68+
.setDeleteAll(false)
69+
.build();
70+
blockingStub.delete(deleteRequest);
71+
Thread.sleep(3500);
72+
73+
// Call describeIndexStats to get updated counts
74+
describeIndexStatsResponse = blockingStub.describeIndexStats(describeIndexRequest);
75+
// Verify the updated vector count
76+
assertEquals(describeIndexStatsResponse.getNamespacesMap().get(namespace).getVectorCount(), startVectorCount - idsToDelete.length);
77+
}
78+
79+
@Test
80+
public void UpsertVectorsAndDeleteByNamespaceSyncTest() throws InterruptedException {
81+
// Upsert vectors with optional parameters
82+
String namespace = RandomStringBuilder.build("ns", 8);
83+
UpsertResponse upsertResponse = blockingStub.upsert(buildOptionalUpsertRequest(namespace));
84+
Thread.sleep(3500);
85+
// Get vector count before deleting vectors
86+
DescribeIndexStatsRequest describeIndexRequest = DescribeIndexStatsRequest.newBuilder().build();
87+
DescribeIndexStatsResponse describeIndexStatsResponse = blockingStub.describeIndexStats(describeIndexRequest);
88+
int startVectorCount = describeIndexStatsResponse.getNamespacesMap().get(namespace).getVectorCount();
89+
assertEquals(startVectorCount, upsertResponse.getUpsertedCount());
90+
91+
// Delete all vectors in the namespace
92+
DeleteRequest deleteRequest = DeleteRequest.newBuilder()
93+
.setNamespace(namespace)
94+
.setDeleteAll(true)
95+
.build();
96+
blockingStub.delete(deleteRequest);
97+
Thread.sleep(3500);
98+
99+
// Call describeIndexStats to get updated counts
100+
NamespaceSummary namespaceSummary = blockingStub.describeIndexStats(describeIndexRequest).getNamespacesMap().get(namespace);
101+
// Verify the namespace is deleted
102+
assertThrows(NullPointerException.class, () -> namespaceSummary.getVectorCount());
103+
}
104+
105+
@Test
106+
public void UpsertVectorsAndDeleteByFilterSyncTest() throws InterruptedException {
107+
// Upsert vectors with optional and custom metadata parameters
108+
String namespace = RandomStringBuilder.build("ns", 8);
109+
UpsertResponse upsertResponse = blockingStub.upsert(buildOptionalUpsertRequest(namespace));
110+
Thread.sleep(3500);
111+
String fieldToDelete = metadataFields[0];
112+
String valueToDelete = createAndGetMetadataMap().get(fieldToDelete).get(0);
113+
114+
// Get vector count before deleting vectors
115+
DescribeIndexStatsRequest describeIndexRequest = DescribeIndexStatsRequest.newBuilder().build();
116+
DescribeIndexStatsResponse describeIndexStatsResponse = blockingStub.describeIndexStats(describeIndexRequest);
117+
int startVectorCount = describeIndexStatsResponse.getNamespacesMap().get(namespace).getVectorCount();
118+
assertEquals(upsertResponse.getUpsertedCount(), startVectorCount);
119+
120+
// Delete by filtering
121+
DeleteRequest deleteRequest = DeleteRequest.newBuilder()
122+
.setNamespace(namespace)
123+
.setDeleteAll(false)
124+
.setFilter(Struct.newBuilder()
125+
.putFields(fieldToDelete, Value.newBuilder()
126+
.setStructValue(Struct.newBuilder()
127+
.putFields("$eq", Value.newBuilder()
128+
.setStringValue(valueToDelete)
129+
.build()))
130+
.build())
131+
.build())
132+
.build();
133+
blockingStub.delete(deleteRequest);
134+
Thread.sleep(3500);
135+
136+
// Call describeIndexStats to get updated counts
137+
NamespaceSummary namespaceSummary = blockingStub.describeIndexStats(describeIndexRequest).getNamespacesMap().get(namespace);
138+
// Verify the updated vector count
139+
assertEquals(namespaceSummary.getVectorCount(), upsertResponse.getUpsertedCount() - 1);
140+
}
141+
142+
@Test
143+
public void UpsertVectorsAndDeleteByIdFutureTest() throws ExecutionException, InterruptedException {
144+
// Upsert vectors with required parameters
145+
String namespace = RandomStringBuilder.build("ns", 8);
146+
List<String> upsertIds = Arrays.asList("v1", "v2", "v3");
147+
UpsertResponse upsertResponse = futureStub.upsert(buildRequiredUpsertRequest(upsertIds, namespace)).get();
148+
Thread.sleep(3500);
149+
150+
// Get vector count before deleting vectors
151+
DescribeIndexStatsRequest describeIndexRequest = DescribeIndexStatsRequest.newBuilder().build();
152+
DescribeIndexStatsResponse describeIndexStatsResponse = blockingStub.describeIndexStats(describeIndexRequest);
153+
int startVectorCount = describeIndexStatsResponse.getNamespacesMap().get(namespace).getVectorCount();
154+
assertEquals(startVectorCount, upsertResponse.getUpsertedCount());
155+
156+
// Delete 1 vector
157+
String[] idsToDelete = new String[]{upsertIds.get(0)};
158+
DeleteRequest deleteRequest = DeleteRequest.newBuilder()
159+
.setNamespace(namespace)
160+
.addAllIds(Arrays.asList(idsToDelete))
161+
.setDeleteAll(false)
162+
.build();
163+
blockingStub.delete(deleteRequest);
164+
Thread.sleep(3500);
165+
166+
// Call describeIndexStats to get updated counts
167+
describeIndexStatsResponse = futureStub.describeIndexStats(describeIndexRequest).get();
168+
assertEquals(describeIndexStatsResponse.getNamespacesMap().get(namespace).getVectorCount(), startVectorCount - idsToDelete.length);
169+
startVectorCount -= idsToDelete.length;
170+
171+
// Delete multiple vectors
172+
idsToDelete = new String[]{upsertIds.get(1), upsertIds.get(2)};
173+
deleteRequest = DeleteRequest.newBuilder()
174+
.setNamespace(namespace)
175+
.addAllIds(Arrays.asList(idsToDelete))
176+
.setDeleteAll(false)
177+
.build();
178+
blockingStub.delete(deleteRequest);
179+
Thread.sleep(3500);
180+
181+
// Call describeIndexStats to get updated counts
182+
describeIndexStatsResponse = futureStub.describeIndexStats(describeIndexRequest).get();
183+
// Verify the updated vector count
184+
assertEquals(describeIndexStatsResponse.getNamespacesMap().get(namespace).getVectorCount(), startVectorCount - idsToDelete.length);
185+
}
186+
187+
@Test
188+
public void UpsertVectorsAndDeleteByNamespaceFutureTest() throws ExecutionException, InterruptedException {
189+
// Upsert vectors with optional parameters
190+
String namespace = RandomStringBuilder.build("ns", 8);
191+
UpsertResponse upsertResponse = futureStub.upsert(buildOptionalUpsertRequest(namespace)).get();
192+
Thread.sleep(3500);
193+
194+
// Get vector count before deleting vectors
195+
DescribeIndexStatsRequest describeIndexRequest = DescribeIndexStatsRequest.newBuilder().build();
196+
DescribeIndexStatsResponse describeIndexStatsResponse = futureStub.describeIndexStats(describeIndexRequest).get();
197+
int startVectorCount = describeIndexStatsResponse.getNamespacesMap().get(namespace).getVectorCount();
198+
assertEquals(startVectorCount, upsertResponse.getUpsertedCount());
199+
200+
// Delete all vectors in the namespace
201+
DeleteRequest deleteRequest = DeleteRequest.newBuilder()
202+
.setNamespace(namespace)
203+
.setDeleteAll(true)
204+
.build();
205+
futureStub.delete(deleteRequest);
206+
Thread.sleep(3500);
207+
208+
// Call describeIndexStats to get updated counts
209+
NamespaceSummary namespaceSummary = futureStub.describeIndexStats(describeIndexRequest).get().getNamespacesMap().get(namespace);
210+
// Verify the namespace is deleted
211+
assertThrows(NullPointerException.class, () -> namespaceSummary.getVectorCount());
212+
}
213+
214+
@Test
215+
public void UpsertVectorsAndDeleteByFilterFutureTest() throws InterruptedException, ExecutionException {
216+
// Upsert vectors with optional and custom metadata parameters
217+
String namespace = RandomStringBuilder.build("ns", 8);
218+
String fieldToDelete = metadataFields[0];
219+
String valueToDelete = createAndGetMetadataMap().get(fieldToDelete).get(0);
220+
UpsertResponse upsertResponse = futureStub.upsert(buildOptionalUpsertRequest(namespace)).get();
221+
Thread.sleep(3500);
222+
223+
// Get vector count before deleting vectors
224+
DescribeIndexStatsRequest describeIndexRequest = DescribeIndexStatsRequest.newBuilder().build();
225+
DescribeIndexStatsResponse describeIndexStatsResponse = futureStub.describeIndexStats(describeIndexRequest).get();
226+
int startVectorCount = describeIndexStatsResponse.getNamespacesMap().get(namespace).getVectorCount();
227+
assertEquals(upsertResponse.getUpsertedCount(), startVectorCount);
228+
229+
// Delete by filtering
230+
DeleteRequest deleteRequest = DeleteRequest.newBuilder()
231+
.setNamespace(namespace)
232+
.setDeleteAll(false)
233+
.setFilter(Struct.newBuilder()
234+
.putFields(metadataFields[0], Value.newBuilder()
235+
.setStructValue(Struct.newBuilder()
236+
.putFields("$eq", Value.newBuilder()
237+
.setStringValue(valueToDelete)
238+
.build()))
239+
.build())
240+
.build())
241+
.build();
242+
futureStub.delete(deleteRequest);
243+
Thread.sleep(3500);
244+
245+
// Call describeIndexStats to get updated counts
246+
NamespaceSummary namespaceSummary = futureStub.describeIndexStats(describeIndexRequest).get().getNamespacesMap().get(namespace);
247+
// Verify the updated vector count
248+
assertEquals(namespaceSummary.getVectorCount(), upsertResponse.getUpsertedCount() - 1);
249+
}
250+
}

0 commit comments

Comments
 (0)