Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v1.7.0 #13

Merged
merged 12 commits into from
Dec 21, 2023
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