Skip to content

Commit

Permalink
v1.11.0 (#48)
Browse files Browse the repository at this point in the history
Co-authored-by: Anush  <[email protected]>
Co-authored-by: Tim Visée <[email protected]>
  • Loading branch information
Anush008 and timvisee authored Aug 12, 2024
1 parent 60bba58 commit b229554
Show file tree
Hide file tree
Showing 6 changed files with 131 additions and 10 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,20 +34,20 @@ To install the library, add the following lines to your build config file.
<dependency>
<groupId>io.qdrant</groupId>
<artifactId>client</artifactId>
<version>1.10.0</version>
<version>1.11.0</version>
</dependency>
```

#### SBT

```sbt
libraryDependencies += "io.qdrant" % "client" % "1.10.0"
libraryDependencies += "io.qdrant" % "client" % "1.11.0"
```

#### Gradle

```gradle
implementation 'io.qdrant:client:1.10.0'
implementation 'io.qdrant:client:1.11.0'
```

> [!NOTE]
Expand Down
9 changes: 3 additions & 6 deletions gradle.properties
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
# The version of qdrant to use to download protos
qdrantProtosVersion=v1.10.0
qdrantProtosVersion=v1.11.0

# The version of qdrant docker image to run integration tests against
qdrantVersion=v1.10.0
qdrantVersion=v1.11.0

# The version of the client to generate
packageVersion=1.10.0

## Extension of the default memory config for the spotless formatter plugin
org.gradle.jvmargs= -Xmx2000m "-XX:MaxMetaspaceSize=1000m"
packageVersion=1.11.0
33 changes: 33 additions & 0 deletions src/main/java/io/qdrant/client/QdrantClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@
import io.qdrant.client.grpc.Points.PointsUpdateOperation;
import io.qdrant.client.grpc.Points.QueryBatchPoints;
import io.qdrant.client.grpc.Points.QueryBatchResponse;
import io.qdrant.client.grpc.Points.QueryGroupsResponse;
import io.qdrant.client.grpc.Points.QueryPointGroups;
import io.qdrant.client.grpc.Points.QueryPoints;
import io.qdrant.client.grpc.Points.QueryResponse;
import io.qdrant.client.grpc.Points.ReadConsistency;
Expand Down Expand Up @@ -2771,6 +2773,37 @@ public ListenableFuture<List<BatchResult>> queryBatchAsync(
future, QueryBatchResponse::getResultList, MoreExecutors.directExecutor());
}

/**
* Universally query points. Covers all capabilities of search, recommend, discover, filters.
* Grouped by a payload field.
*
* @param request the query request
* @return a new instance of {@link ListenableFuture}
*/
public ListenableFuture<List<PointGroup>> queryGroupsAsync(QueryPointGroups request) {
return queryGroupsAsync(request, null);
}

/**
* Universally query points. Covers all capabilities of search, recommend, discover, filters.
* Grouped by a payload field.
*
* @param request the query request
* @param timeout the timeout for the call.
* @return a new instance of {@link ListenableFuture}
*/
public ListenableFuture<List<PointGroup>> queryGroupsAsync(
QueryPointGroups request, @Nullable Duration timeout) {
Preconditions.checkArgument(
!request.getCollectionName().isEmpty(), "Collection name must not be empty");

logger.debug("Query groups on '{}'", request.getCollectionName());
ListenableFuture<QueryGroupsResponse> future = getPoints(timeout).queryGroups(request);
addLogFailureCallback(future, "Query groups");
return Futures.transform(
future, response -> response.getResult().getGroupsList(), MoreExecutors.directExecutor());
}

// region Snapshot Management

/**
Expand Down
11 changes: 11 additions & 0 deletions src/main/java/io/qdrant/client/QueryFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import io.qdrant.client.grpc.Points.PointId;
import io.qdrant.client.grpc.Points.Query;
import io.qdrant.client.grpc.Points.RecommendInput;
import io.qdrant.client.grpc.Points.Sample;
import io.qdrant.client.grpc.Points.VectorInput;
import java.util.List;
import java.util.UUID;
Expand Down Expand Up @@ -172,5 +173,15 @@ public static Query nearestMultiVector(List<List<Float>> vectors) {
return Query.newBuilder().setNearest(multiVectorInput(vectors)).build();
}

/**
* Creates a {@link Query} for sampling.
*
* @param sample An instance of {@link Sample}
* @return A new instance of {@link Query}
*/
public static Query sample(Sample sample) {
return Query.newBuilder().setSample(sample).build();
}

// endregion
}
24 changes: 24 additions & 0 deletions src/main/java/io/qdrant/client/ValueFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@

import io.qdrant.client.grpc.JsonWithInt.ListValue;
import io.qdrant.client.grpc.JsonWithInt.NullValue;
import io.qdrant.client.grpc.JsonWithInt.Struct;
import io.qdrant.client.grpc.JsonWithInt.Value;
import java.util.List;
import java.util.Map;

/** Convenience methods for constructing {@link Value} */
public final class ValueFactory {
Expand Down Expand Up @@ -69,4 +71,26 @@ public static Value list(List<Value> values) {
.setListValue(ListValue.newBuilder().addAllValues(values).build())
.build();
}

/**
* Creates a value from a list of values. Same as {@link #list(List)}
*
* @param values The list of values
* @return a new instance of {@link io.qdrant.client.grpc.JsonWithInt.Value}
*/
public static Value value(List<Value> values) {
return list(values);
}

/**
* Creates a value from a map of nested values
*
* @param values The map of values
* @return a new instance of {@link io.qdrant.client.grpc.JsonWithInt.Value}
*/
public static Value value(Map<String, Value> values) {
return Value.newBuilder()
.setStructValue(Struct.newBuilder().putAllFields(values).build())
.build();
}
}
58 changes: 57 additions & 1 deletion src/test/java/io/qdrant/client/PointsTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import static io.qdrant.client.QueryFactory.fusion;
import static io.qdrant.client.QueryFactory.nearest;
import static io.qdrant.client.QueryFactory.orderBy;
import static io.qdrant.client.QueryFactory.sample;
import static io.qdrant.client.TargetVectorFactory.targetVector;
import static io.qdrant.client.ValueFactory.value;
import static io.qdrant.client.VectorFactory.vector;
Expand Down Expand Up @@ -38,10 +39,12 @@
import io.qdrant.client.grpc.Points.PointsUpdateOperation.ClearPayload;
import io.qdrant.client.grpc.Points.PointsUpdateOperation.UpdateVectors;
import io.qdrant.client.grpc.Points.PrefetchQuery;
import io.qdrant.client.grpc.Points.QueryPointGroups;
import io.qdrant.client.grpc.Points.QueryPoints;
import io.qdrant.client.grpc.Points.RecommendPointGroups;
import io.qdrant.client.grpc.Points.RecommendPoints;
import io.qdrant.client.grpc.Points.RetrievedPoint;
import io.qdrant.client.grpc.Points.Sample;
import io.qdrant.client.grpc.Points.ScoredPoint;
import io.qdrant.client.grpc.Points.ScrollPoints;
import io.qdrant.client.grpc.Points.ScrollResponse;
Expand All @@ -50,6 +53,7 @@
import io.qdrant.client.grpc.Points.UpdateResult;
import io.qdrant.client.grpc.Points.UpdateStatus;
import io.qdrant.client.grpc.Points.Vectors;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
Expand Down Expand Up @@ -596,7 +600,7 @@ public void batchPointUpdate() throws ExecutionException, InterruptedException {
createAndSeedCollection(testName);

List<PointsUpdateOperation> operations =
List.of(
Arrays.asList(
PointsUpdateOperation.newBuilder()
.setClearPayload(
ClearPayload.newBuilder()
Expand Down Expand Up @@ -757,6 +761,58 @@ public void queryWithPrefetchAndFusion() throws ExecutionException, InterruptedE
assertEquals(2, points.size());
}

@Test
public void queryWithSampling() throws ExecutionException, InterruptedException {
createAndSeedCollection(testName);

List<ScoredPoint> points =
client
.queryAsync(
QueryPoints.newBuilder()
.setCollectionName(testName)
.setQuery(sample(Sample.Random))
.setLimit(1)
.build())
.get();

assertEquals(1, points.size());
}

@Test
public void queryGroups() throws ExecutionException, InterruptedException {
createAndSeedCollection(testName);

client
.upsertAsync(
testName,
ImmutableList.of(
PointStruct.newBuilder()
.setId(id(10))
.setVectors(VectorsFactory.vectors(30f, 31f))
.putAllPayload(ImmutableMap.of("foo", value("hello")))
.build()))
.get();
// 3 points in total, 2 with "foo" = "hello" and 1 with "foo" = "goodbye"

List<PointGroup> groups =
client
.queryGroupsAsync(
QueryPointGroups.newBuilder()
.setCollectionName(testName)
.setQuery(nearest(ImmutableList.of(10.4f, 11.4f)))
.setGroupBy("foo")
.setGroupSize(2)
.setLimit(10)
.build())
.get();

assertEquals(2, groups.size());
// A group with 2 hits because of 2 points with "foo" = "hello"
assertEquals(1, groups.stream().filter(g -> g.getHitsCount() == 2).count());
// A group with 1 hit because of 1 point with "foo" = "goodbye"
assertEquals(1, groups.stream().filter(g -> g.getHitsCount() == 1).count());
}

private void createAndSeedCollection(String collectionName)
throws ExecutionException, InterruptedException {
CreateCollection request =
Expand Down

0 comments on commit b229554

Please sign in to comment.