Skip to content

Commit

Permalink
v1.7.0 (#13)
Browse files Browse the repository at this point in the history
* feat: ShardKeyFactory

* feat: ShardKeySelectorFactory

* feat: shard key ops

* feat: shard key ops overloads

* feat: discover ops

* refactor: upade discoverBatchAsync

* feat: targetVectorFactory, VectorFactory

* test: discover searches

* refactor: VectorsFactory to use vector()

* Apply suggestions from code review

Co-authored-by: Russ Cam <russ.cam@forloop.co.uk>

* chore: review changes

* docs: Update README.md version

---------

Co-authored-by: Anush <anush@Anushs-Air-M2.local>
Co-authored-by: Russ Cam <russ.cam@forloop.co.uk>
  • Loading branch information
3 people authored Dec 21, 2023
1 parent dc75e03 commit 8d37efd
Show file tree
Hide file tree
Showing 10 changed files with 393 additions and 25 deletions.
8 changes: 3 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@ Java client library with handy utility methods and overloads for interfacing wit

## 📥 Installation

> Not yet published.
> [!IMPORTANT]
> Requires Java 8 or above.
Expand All @@ -36,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.7-SNAPSHOT</version>
<version>1.7.0</version>
</dependency>
```

#### Scala SBT

```sbt
libraryDependencies += "io.qdrant" % "client" % "1.7-SNAPSHOT"
libraryDependencies += "io.qdrant" % "client" % "1.7.0"
```

#### Gradle

```gradle
implementation 'io.qdrant:client:1.7-SNAPSHOT'
implementation 'io.qdrant:client:1.7.0'
```

## 📖 Documentation
Expand Down
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -228,4 +228,4 @@ publishing {
repositories {
mavenLocal()
}
}
}
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ qdrantProtosVersion=v1.7.0
qdrantVersion=v1.7.0

# The version of the client to generate
packageVersion=1.7-SNAPSHOT
packageVersion=1.7.0
164 changes: 164 additions & 0 deletions src/main/java/io/qdrant/client/QdrantClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import io.qdrant.client.grpc.CollectionsGrpc;
import io.qdrant.client.grpc.PointsGrpc;
import io.qdrant.client.grpc.SnapshotsGrpc;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand All @@ -28,8 +29,16 @@
import static io.qdrant.client.grpc.Collections.CollectionOperationResponse;
import static io.qdrant.client.grpc.Collections.CreateAlias;
import static io.qdrant.client.grpc.Collections.CreateCollection;
import static io.qdrant.client.grpc.Collections.CreateShardKeyRequest;
import static io.qdrant.client.grpc.Collections.CreateShardKeyResponse;
import static io.qdrant.client.grpc.Collections.DeleteAlias;
import static io.qdrant.client.grpc.Collections.DeleteCollection;
import static io.qdrant.client.grpc.Collections.DeleteShardKeyRequest;
import static io.qdrant.client.grpc.Collections.DeleteShardKeyResponse;
import static io.qdrant.client.grpc.Points.DiscoverBatchPoints;
import static io.qdrant.client.grpc.Points.DiscoverBatchResponse;
import static io.qdrant.client.grpc.Points.DiscoverPoints;
import static io.qdrant.client.grpc.Points.DiscoverResponse;
import static io.qdrant.client.grpc.Collections.GetCollectionInfoRequest;
import static io.qdrant.client.grpc.Collections.GetCollectionInfoResponse;
import static io.qdrant.client.grpc.Collections.ListAliasesRequest;
Expand All @@ -40,6 +49,7 @@
import static io.qdrant.client.grpc.Collections.PayloadIndexParams;
import static io.qdrant.client.grpc.Collections.PayloadSchemaType;
import static io.qdrant.client.grpc.Collections.RenameAlias;
import static io.qdrant.client.grpc.Collections.ShardKey;
import static io.qdrant.client.grpc.Collections.UpdateCollection;
import static io.qdrant.client.grpc.Collections.VectorParams;
import static io.qdrant.client.grpc.Collections.VectorParamsMap;
Expand Down Expand Up @@ -665,6 +675,78 @@ public ListenableFuture<List<AliasDescription>> listAliasesAsync(@Nullable Durat

//endregion

//region ShardKey Management

/**
* Creates a shard key for a collection.
*
* @param createShardKey The request object for the operation.
* @return a new instance of {@link ListenableFuture}
*/
public ListenableFuture<CreateShardKeyResponse> createShardKeyAsync(CreateShardKeyRequest createShardKey) {
return createShardKeyAsync(createShardKey, null);
}

/**
* Creates a shard key for a collection.
*
* @param createShardKey The request object for the operation.
* @param timeout The timeout for the call.
* @return a new instance of {@link ListenableFuture}
*/
public ListenableFuture<CreateShardKeyResponse> createShardKeyAsync(CreateShardKeyRequest createShardKey, @Nullable Duration timeout) {
String collectionName = createShardKey.getCollectionName();
Preconditions.checkArgument(!collectionName.isEmpty(), "Collection name must not be empty");
ShardKey shardKey = createShardKey.getRequest().getShardKey();
logger.debug("Create shard key '{}' for '{}'", shardKey, collectionName);

ListenableFuture<CreateShardKeyResponse> future = getCollections(timeout).createShardKey(createShardKey);
addLogFailureCallback(future, "Create shard key");
return Futures.transform(future, response -> {
if (!response.getResult()) {
logger.error("Shard key could not be created for '{}'", collectionName);
throw new QdrantException("Shard key " + shardKey + " could not be created for " + collectionName);
}
return response;
}, MoreExecutors.directExecutor());
}

/**
* Deletes a shard key for a collection.
*
* @param deleteShardKey The request object for the operation.
* @return a new instance of {@link ListenableFuture}
*/
public ListenableFuture<DeleteShardKeyResponse> deleteShardKeyAsync(DeleteShardKeyRequest deleteShardKey) {
return deleteShardKeyAsync(deleteShardKey, null);
}

/**
* Deletes a shard key for a collection.
*
* @param deleteShardKey The request object for the operation.
* @param timeout The timeout for the call.
* @return a new instance of {@link ListenableFuture}
*/
public ListenableFuture<DeleteShardKeyResponse> deleteShardKeyAsync(DeleteShardKeyRequest deleteShardKey, @Nullable Duration timeout) {
String collectionName = deleteShardKey.getCollectionName();
Preconditions.checkArgument(!collectionName.isEmpty(), "Collection name must not be empty");
ShardKey shardKey = deleteShardKey.getRequest().getShardKey();
logger.debug("Delete shard key '{}' for '{}'", shardKey, collectionName);

ListenableFuture<DeleteShardKeyResponse> future = getCollections(timeout).deleteShardKey(deleteShardKey);
addLogFailureCallback(future, "Delete shard key");
return Futures.transform(future, response -> {
if (!response.getResult()) {
logger.error("Shard key '{}' could not be deleted for '{}'", shardKey, collectionName);
throw new QdrantException("Shard key " + shardKey + " could not be created for " + collectionName);
}
return response;
}, MoreExecutors.directExecutor());
}

//endregion

//region Point Management

/**
Expand Down Expand Up @@ -2153,6 +2235,88 @@ public ListenableFuture<List<PointGroup>> recommendGroupsAsync(RecommendPointGro
MoreExecutors.directExecutor());
}

/**
* Use the context and a target to find the most similar points to the target.
* Constraints by the context.
*
* @param request The discover points request
* @return a new instance of {@link ListenableFuture}
*/
public ListenableFuture<List<ScoredPoint>> discoverAsync(DiscoverPoints request) {
return discoverAsync(request, null);
}

/**
* Use the context and a target to find the most similar points to the target.
* Constraints by the context.
*
* @param request The discover points request
* @param timeout The timeout for the call.
* @return a new instance of {@link ListenableFuture}
*/
public ListenableFuture<List<ScoredPoint>> discoverAsync(DiscoverPoints request, @Nullable Duration timeout) {
String collectionName = request.getCollectionName();
Preconditions.checkArgument(!collectionName.isEmpty(), "Collection name must not be empty");
logger.debug("Discover on '{}'", collectionName);
ListenableFuture<DiscoverResponse> future = getPoints(timeout).discover(request);
addLogFailureCallback(future, "Discover");
return Futures.transform(
future,
response -> response.getResultList(),
MoreExecutors.directExecutor());
}

/**
* Use the context and a target to find the most similar points to the target in
* a batch.
* Constrained by the context.
*
* @param collectionName The name of the collection
* @param discoverSearches The list for discover point searches
* @param readConsistency Options for specifying read consistency guarantees
* @return a new instance of {@link ListenableFuture}
*/
public ListenableFuture<List<BatchResult>> discoverBatchAsync(
String collectionName,
List<DiscoverPoints> discoverSearches,
@Nullable ReadConsistency readConsistency) {
return discoverBatchAsync(collectionName, discoverSearches, readConsistency, null);
}

/**
* Use the context and a target to find the most similar points to the target in
* a batch.
* Constrained by the context.
*
* @param collectionName The name of the collection
* @param discoverSearches The list for discover point searches
* @param readConsistency Options for specifying read consistency guarantees
* @param timeout The timeout for the call.
* @return a new instance of {@link ListenableFuture}
*/
public ListenableFuture<List<BatchResult>> discoverBatchAsync(
String collectionName,
List<DiscoverPoints> discoverSearches,
@Nullable ReadConsistency readConsistency,
@Nullable Duration timeout) {
Preconditions.checkArgument(!collectionName.isEmpty(), "Collection name must not be empty");

DiscoverBatchPoints.Builder requestBuilder = DiscoverBatchPoints.newBuilder()
.setCollectionName(collectionName)
.addAllDiscoverPoints(discoverSearches);

if (readConsistency != null) {
requestBuilder.setReadConsistency(readConsistency);
}
logger.debug("Discover batch on '{}'", collectionName);
ListenableFuture<DiscoverBatchResponse> future = getPoints(timeout).discoverBatch(requestBuilder.build());
addLogFailureCallback(future, "Discover batch");
return Futures.transform(
future,
response -> response.getResultList(),
MoreExecutors.directExecutor());
}

/**
* Count the points in a collection. The count is exact
*
Expand Down
31 changes: 31 additions & 0 deletions src/main/java/io/qdrant/client/ShardKeyFactory.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package io.qdrant.client;

import io.qdrant.client.grpc.Collections.ShardKey;

/**
* Convenience methods for constructing {@link ShardKey}
*/
public final class ShardKeyFactory {
private ShardKeyFactory() {
}

/**
* Creates a {@link ShardKey} based on a keyword.
*
* @param keyword The keyword to create the shard key from
* @return The {@link ShardKey} object
*/
public static ShardKey shardKey(String keyword) {
return ShardKey.newBuilder().setKeyword(keyword).build();
}

/**
* Creates a {@link ShardKey} based on a number.
*
* @param number The number to create the shard key from
* @return The {@link ShardKey} object
*/
public static ShardKey shardKey(long number) {
return ShardKey.newBuilder().setNumber(number).build();
}
}
54 changes: 54 additions & 0 deletions src/main/java/io/qdrant/client/ShardKeySelectorFactory.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package io.qdrant.client;

import io.qdrant.client.grpc.Collections.ShardKey;
import io.qdrant.client.grpc.Points.ShardKeySelector;

import static io.qdrant.client.ShardKeyFactory.shardKey;

import java.util.Arrays;

/**
* Convenience methods for constructing {@link ShardKeySelector}
*/
public class ShardKeySelectorFactory {
private ShardKeySelectorFactory() {
}

/**
* Creates a {@link ShardKeySelector} with the given shard keys.
*
* @param shardKeys The shard keys to include in the selector.
* @return The created {@link ShardKeySelector} object.
*/
public static ShardKeySelector shardKeySelector(ShardKey... shardKeys) {
return ShardKeySelector.newBuilder().addAllShardKeys(Arrays.asList(shardKeys)).build();
}

/**
* Creates a {@link ShardKeySelector} with the given shard key keywords.
*
* @param keywords The shard key keywords to include in the selector.
* @return The created {@link ShardKeySelector} object.
*/
public static ShardKeySelector shardKeySelector(String... keywords) {
ShardKeySelector.Builder builder = ShardKeySelector.newBuilder();
for (String keyword : keywords) {
builder.addShardKeys(shardKey(keyword));
}
return builder.build();
}

/**
* Creates a {@link ShardKeySelector} with the given shard key numbers.
*
* @param numbers The shard key numbers to include in the selector.
* @return The created {@link ShardKeySelector} object.
*/
public static ShardKeySelector shardKeySelector(long... numbers) {
ShardKeySelector.Builder builder = ShardKeySelector.newBuilder();
for (long number : numbers) {
builder.addShardKeys(shardKey(number));
}
return builder.build();
}
}
32 changes: 32 additions & 0 deletions src/main/java/io/qdrant/client/TargetVectorFactory.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package io.qdrant.client;

import io.qdrant.client.grpc.Points.PointId;
import io.qdrant.client.grpc.Points.TargetVector;
import io.qdrant.client.grpc.Points.Vector;
import io.qdrant.client.grpc.Points.VectorExample;

/**
* Convenience methods for constructing {@link TargetVector}
*/
public class TargetVectorFactory {
private TargetVectorFactory() {
}

/**
* Creates a TargetVector from a point ID
* @param id The point ID to use
* @return A new instance of {@link TargetVector}
*/
public static TargetVector targetVector(PointId id) {
return TargetVector.newBuilder().setSingle(VectorExample.newBuilder().setId(id)).build();
}

/**
* Creates a TargetVector from a Vector
* @param vector The Vector value to use
* @return A new instance of {@link TargetVector}
*/
public static TargetVector targetVector(Vector vector) {
return TargetVector.newBuilder().setSingle(VectorExample.newBuilder().setVector(vector)).build();
}
}
Loading

0 comments on commit 8d37efd

Please sign in to comment.