Skip to content

Commit b229554

Browse files
Anush008timvisee
andauthored
v1.11.0 (#48)
Co-authored-by: Anush <[email protected]> Co-authored-by: Tim Visée <[email protected]>
1 parent 60bba58 commit b229554

File tree

6 files changed

+131
-10
lines changed

6 files changed

+131
-10
lines changed

README.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -34,20 +34,20 @@ To install the library, add the following lines to your build config file.
3434
<dependency>
3535
<groupId>io.qdrant</groupId>
3636
<artifactId>client</artifactId>
37-
<version>1.10.0</version>
37+
<version>1.11.0</version>
3838
</dependency>
3939
```
4040

4141
#### SBT
4242

4343
```sbt
44-
libraryDependencies += "io.qdrant" % "client" % "1.10.0"
44+
libraryDependencies += "io.qdrant" % "client" % "1.11.0"
4545
```
4646

4747
#### Gradle
4848

4949
```gradle
50-
implementation 'io.qdrant:client:1.10.0'
50+
implementation 'io.qdrant:client:1.11.0'
5151
```
5252

5353
> [!NOTE]

gradle.properties

+3-6
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
11
# The version of qdrant to use to download protos
2-
qdrantProtosVersion=v1.10.0
2+
qdrantProtosVersion=v1.11.0
33

44
# The version of qdrant docker image to run integration tests against
5-
qdrantVersion=v1.10.0
5+
qdrantVersion=v1.11.0
66

77
# The version of the client to generate
8-
packageVersion=1.10.0
9-
10-
## Extension of the default memory config for the spotless formatter plugin
11-
org.gradle.jvmargs= -Xmx2000m "-XX:MaxMetaspaceSize=1000m"
8+
packageVersion=1.11.0

src/main/java/io/qdrant/client/QdrantClient.java

+33
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,8 @@
6767
import io.qdrant.client.grpc.Points.PointsUpdateOperation;
6868
import io.qdrant.client.grpc.Points.QueryBatchPoints;
6969
import io.qdrant.client.grpc.Points.QueryBatchResponse;
70+
import io.qdrant.client.grpc.Points.QueryGroupsResponse;
71+
import io.qdrant.client.grpc.Points.QueryPointGroups;
7072
import io.qdrant.client.grpc.Points.QueryPoints;
7173
import io.qdrant.client.grpc.Points.QueryResponse;
7274
import io.qdrant.client.grpc.Points.ReadConsistency;
@@ -2771,6 +2773,37 @@ public ListenableFuture<List<BatchResult>> queryBatchAsync(
27712773
future, QueryBatchResponse::getResultList, MoreExecutors.directExecutor());
27722774
}
27732775

2776+
/**
2777+
* Universally query points. Covers all capabilities of search, recommend, discover, filters.
2778+
* Grouped by a payload field.
2779+
*
2780+
* @param request the query request
2781+
* @return a new instance of {@link ListenableFuture}
2782+
*/
2783+
public ListenableFuture<List<PointGroup>> queryGroupsAsync(QueryPointGroups request) {
2784+
return queryGroupsAsync(request, null);
2785+
}
2786+
2787+
/**
2788+
* Universally query points. Covers all capabilities of search, recommend, discover, filters.
2789+
* Grouped by a payload field.
2790+
*
2791+
* @param request the query request
2792+
* @param timeout the timeout for the call.
2793+
* @return a new instance of {@link ListenableFuture}
2794+
*/
2795+
public ListenableFuture<List<PointGroup>> queryGroupsAsync(
2796+
QueryPointGroups request, @Nullable Duration timeout) {
2797+
Preconditions.checkArgument(
2798+
!request.getCollectionName().isEmpty(), "Collection name must not be empty");
2799+
2800+
logger.debug("Query groups on '{}'", request.getCollectionName());
2801+
ListenableFuture<QueryGroupsResponse> future = getPoints(timeout).queryGroups(request);
2802+
addLogFailureCallback(future, "Query groups");
2803+
return Futures.transform(
2804+
future, response -> response.getResult().getGroupsList(), MoreExecutors.directExecutor());
2805+
}
2806+
27742807
// region Snapshot Management
27752808

27762809
/**

src/main/java/io/qdrant/client/QueryFactory.java

+11
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import io.qdrant.client.grpc.Points.PointId;
1111
import io.qdrant.client.grpc.Points.Query;
1212
import io.qdrant.client.grpc.Points.RecommendInput;
13+
import io.qdrant.client.grpc.Points.Sample;
1314
import io.qdrant.client.grpc.Points.VectorInput;
1415
import java.util.List;
1516
import java.util.UUID;
@@ -172,5 +173,15 @@ public static Query nearestMultiVector(List<List<Float>> vectors) {
172173
return Query.newBuilder().setNearest(multiVectorInput(vectors)).build();
173174
}
174175

176+
/**
177+
* Creates a {@link Query} for sampling.
178+
*
179+
* @param sample An instance of {@link Sample}
180+
* @return A new instance of {@link Query}
181+
*/
182+
public static Query sample(Sample sample) {
183+
return Query.newBuilder().setSample(sample).build();
184+
}
185+
175186
// endregion
176187
}

src/main/java/io/qdrant/client/ValueFactory.java

+24
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@
22

33
import io.qdrant.client.grpc.JsonWithInt.ListValue;
44
import io.qdrant.client.grpc.JsonWithInt.NullValue;
5+
import io.qdrant.client.grpc.JsonWithInt.Struct;
56
import io.qdrant.client.grpc.JsonWithInt.Value;
67
import java.util.List;
8+
import java.util.Map;
79

810
/** Convenience methods for constructing {@link Value} */
911
public final class ValueFactory {
@@ -69,4 +71,26 @@ public static Value list(List<Value> values) {
6971
.setListValue(ListValue.newBuilder().addAllValues(values).build())
7072
.build();
7173
}
74+
75+
/**
76+
* Creates a value from a list of values. Same as {@link #list(List)}
77+
*
78+
* @param values The list of values
79+
* @return a new instance of {@link io.qdrant.client.grpc.JsonWithInt.Value}
80+
*/
81+
public static Value value(List<Value> values) {
82+
return list(values);
83+
}
84+
85+
/**
86+
* Creates a value from a map of nested values
87+
*
88+
* @param values The map of values
89+
* @return a new instance of {@link io.qdrant.client.grpc.JsonWithInt.Value}
90+
*/
91+
public static Value value(Map<String, Value> values) {
92+
return Value.newBuilder()
93+
.setStructValue(Struct.newBuilder().putAllFields(values).build())
94+
.build();
95+
}
7296
}

src/test/java/io/qdrant/client/PointsTest.java

+57-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import static io.qdrant.client.QueryFactory.fusion;
77
import static io.qdrant.client.QueryFactory.nearest;
88
import static io.qdrant.client.QueryFactory.orderBy;
9+
import static io.qdrant.client.QueryFactory.sample;
910
import static io.qdrant.client.TargetVectorFactory.targetVector;
1011
import static io.qdrant.client.ValueFactory.value;
1112
import static io.qdrant.client.VectorFactory.vector;
@@ -38,10 +39,12 @@
3839
import io.qdrant.client.grpc.Points.PointsUpdateOperation.ClearPayload;
3940
import io.qdrant.client.grpc.Points.PointsUpdateOperation.UpdateVectors;
4041
import io.qdrant.client.grpc.Points.PrefetchQuery;
42+
import io.qdrant.client.grpc.Points.QueryPointGroups;
4143
import io.qdrant.client.grpc.Points.QueryPoints;
4244
import io.qdrant.client.grpc.Points.RecommendPointGroups;
4345
import io.qdrant.client.grpc.Points.RecommendPoints;
4446
import io.qdrant.client.grpc.Points.RetrievedPoint;
47+
import io.qdrant.client.grpc.Points.Sample;
4548
import io.qdrant.client.grpc.Points.ScoredPoint;
4649
import io.qdrant.client.grpc.Points.ScrollPoints;
4750
import io.qdrant.client.grpc.Points.ScrollResponse;
@@ -50,6 +53,7 @@
5053
import io.qdrant.client.grpc.Points.UpdateResult;
5154
import io.qdrant.client.grpc.Points.UpdateStatus;
5255
import io.qdrant.client.grpc.Points.Vectors;
56+
import java.util.Arrays;
5357
import java.util.List;
5458
import java.util.concurrent.ExecutionException;
5559
import java.util.concurrent.TimeUnit;
@@ -596,7 +600,7 @@ public void batchPointUpdate() throws ExecutionException, InterruptedException {
596600
createAndSeedCollection(testName);
597601

598602
List<PointsUpdateOperation> operations =
599-
List.of(
603+
Arrays.asList(
600604
PointsUpdateOperation.newBuilder()
601605
.setClearPayload(
602606
ClearPayload.newBuilder()
@@ -757,6 +761,58 @@ public void queryWithPrefetchAndFusion() throws ExecutionException, InterruptedE
757761
assertEquals(2, points.size());
758762
}
759763

764+
@Test
765+
public void queryWithSampling() throws ExecutionException, InterruptedException {
766+
createAndSeedCollection(testName);
767+
768+
List<ScoredPoint> points =
769+
client
770+
.queryAsync(
771+
QueryPoints.newBuilder()
772+
.setCollectionName(testName)
773+
.setQuery(sample(Sample.Random))
774+
.setLimit(1)
775+
.build())
776+
.get();
777+
778+
assertEquals(1, points.size());
779+
}
780+
781+
@Test
782+
public void queryGroups() throws ExecutionException, InterruptedException {
783+
createAndSeedCollection(testName);
784+
785+
client
786+
.upsertAsync(
787+
testName,
788+
ImmutableList.of(
789+
PointStruct.newBuilder()
790+
.setId(id(10))
791+
.setVectors(VectorsFactory.vectors(30f, 31f))
792+
.putAllPayload(ImmutableMap.of("foo", value("hello")))
793+
.build()))
794+
.get();
795+
// 3 points in total, 2 with "foo" = "hello" and 1 with "foo" = "goodbye"
796+
797+
List<PointGroup> groups =
798+
client
799+
.queryGroupsAsync(
800+
QueryPointGroups.newBuilder()
801+
.setCollectionName(testName)
802+
.setQuery(nearest(ImmutableList.of(10.4f, 11.4f)))
803+
.setGroupBy("foo")
804+
.setGroupSize(2)
805+
.setLimit(10)
806+
.build())
807+
.get();
808+
809+
assertEquals(2, groups.size());
810+
// A group with 2 hits because of 2 points with "foo" = "hello"
811+
assertEquals(1, groups.stream().filter(g -> g.getHitsCount() == 2).count());
812+
// A group with 1 hit because of 1 point with "foo" = "goodbye"
813+
assertEquals(1, groups.stream().filter(g -> g.getHitsCount() == 1).count());
814+
}
815+
760816
private void createAndSeedCollection(String collectionName)
761817
throws ExecutionException, InterruptedException {
762818
CreateCollection request =

0 commit comments

Comments
 (0)