docs: C# client usage (#599)

* docs: C# client usage part-1

* docs: used named arguments

* docs: filtering operator overload comment
This commit is contained in:
Anush
2024-02-15 16:17:54 +05:30
committed by GitHub
parent 914a88cdb0
commit 1fa6a93f0d
12 changed files with 1321 additions and 19 deletions
@@ -56,7 +56,7 @@ const client = new QdrantClient({
using Qdrant.Client;
var client = new QdrantClient(
"xyz-example.eu-central.aws.cloud.qdrant.io",
host: "xyz-example.eu-central.aws.cloud.qdrant.io",
https: true,
apiKey: "<paste-your-api-key-here>"
);
@@ -63,7 +63,7 @@ const client = new QdrantClient({
using Qdrant.Client;
var client = new QdrantClient(
"xyz-example.eu-central.aws.cloud.qdrant.io",
host: "xyz-example.eu-central.aws.cloud.qdrant.io",
https: true,
apiKey: "<paste-your-api-key-here>"
);
@@ -115,8 +115,20 @@ import io.qdrant.client.QdrantGrpcClient;
QdrantClient client = new QdrantClient(
QdrantGrpcClient.newBuilder("localhost", 6334, false).build());
client.createCollectionAsync("test_collection",
VectorParams.newBuilder().setDistance(Distance.Dot).setSize(4).build()).get();
client.createCollectionAsync("{collection_name}",
VectorParams.newBuilder().setDistance(Distance.Cosine).setSize(100).build()).get();
```
```csharp
using Qdrant.Client;
using Qdrant.Client.Grpc;
var client = new QdrantClient("localhost", 6334);
await client.CreateCollectionAsync(
collectionName: "{collection_name}",
vectorsConfig: new VectorParams { Size = 100, Distance = Distance.Cosine }
);
```
In addition to the required options, you can also specify custom values for the following collection options:
@@ -254,6 +266,19 @@ client
.get();
```
```csharp
using Qdrant.Client;
using Qdrant.Client.Grpc;
var client = new QdrantClient("localhost", 6334);
await client.CreateCollectionAsync(
collectionName: "{collection_name}",
vectorsConfig: new VectorParams { Size = 100, Distance = Distance.Cosine },
initFromCollection: "{from_collection_name}"
);
```
### Collection with multiple vectors
*Available as of v0.10.0*
@@ -388,6 +413,25 @@ client
.get();
```
```csharp
using Qdrant.Client;
using Qdrant.Client.Grpc;
var client = new QdrantClient("localhost", 6334);
await client.CreateCollectionAsync(
collectionName: "{collection_name}",
vectorsConfig: new VectorParamsMap
{
Map =
{
["image"] = new VectorParams { Size = 4, Distance = Distance.Dot },
["text"] = new VectorParams { Size = 8, Distance = Distance.Cosine },
}
}
);
```
For rare use cases, it is possible to create a collection without any vector storage.
*Available as of v1.1.1*
@@ -516,6 +560,18 @@ client
.get();
```
```csharp
using Qdrant.Client;
using Qdrant.Client.Grpc;
var client = new QdrantClient("localhost", 6334);
await client.CreateCollectionAsync(
collectionName: "{collection_name}",
sparseVectorsConfig: ("text", new SparseVectorParams())
);
```
Outside of a unique name, there are no required configuration parameters for sparse vectors.
The distance function for sparse vectors is always `Dot` and does not need to be specified.
@@ -554,6 +610,14 @@ QdrantClient client =
client.deleteCollectionAsync("{collection_name}").get();
```
```csharp
using Qdrant.Client;
var client = new QdrantClient("localhost", 6334);
await client.DeleteCollectionAsync("{collection_name}");
```
### Update collection parameters
Dynamic parameter updates may be helpful, for example, for more efficient initial loading of vectors.
@@ -628,6 +692,18 @@ client.updateCollectionAsync(
.build());
```
```csharp
using Qdrant.Client;
using Qdrant.Client.Grpc;
var client = new QdrantClient("localhost", 6334);
await client.UpdateCollectionAsync(
collectionName: "{collection_name}",
optimizersConfig: new OptimizersConfigDiff { IndexingThreshold = 10000 }
);
```
The following parameters can be updated:
* `optimizers_config` - see [optimizer](../optimizer/) for details.
@@ -924,6 +1000,40 @@ client
.get();
```
```csharp
using Qdrant.Client;
using Qdrant.Client.Grpc;
var client = new QdrantClient("localhost", 6334);
await client.UpdateCollectionAsync(
collectionName: "{collection_name}",
hnswConfig: new HnswConfigDiff { EfConstruct = 123 },
vectorsConfig: new VectorParamsDiffMap
{
Map =
{
{
"my_vector",
new VectorParamsDiff
{
HnswConfig = new HnswConfigDiff { M = 3, EfConstruct = 123 }
}
}
}
},
quantizationConfig: new QuantizationConfigDiff
{
Scalar = new ScalarQuantization
{
Type = QuantizationType.Int8,
Quantile = 0.8f,
AlwaysRam = true
}
}
);
```
## Collection info
Qdrant allows determining the configuration parameters of an existing collection to better understand how the points are
@@ -1009,6 +1119,10 @@ client.getCollectionInfoAsync("{collection_name}").get();
```csharp
await client.GetCollectionInfoAsync("{collection_name}");
```
If you insert the vectors into the collection, the `status` field may become
`yellow` whilst it is optimizing. It will become `green` once all the points are
successfully processed.
@@ -1133,6 +1247,10 @@ client.create_alias("example_collection", "production_collection").await?;
client.createAliasAsync("production_collection", "example_collection").get();
```
```csharp
await client.CreateAliasAsync(aliasName: "production_collection", collectionName: "example_collection");
```
### Remove alias
```bash
@@ -1193,6 +1311,10 @@ client.delete_alias("production_collection").await?;
client.deleteAliasAsync("production_collection").get();
```
```csharp
await client.DeleteAliasAsync("production_collection");
```
### Switch collection
Multiple alias actions are performed atomically.
@@ -1280,6 +1402,10 @@ client.deleteAliasAsync("production_collection").get();
client.createAliasAsync("production_collection", "example_collection").get();
```
```csharp
await client.DeleteAliasAsync("production_collection");
await client.CreateAliasAsync(aliasName: "production_collection", collectionName: "example_collection");
```
### List collection aliases
```http
@@ -1324,6 +1450,14 @@ QdrantClient client =
client.listCollectionAliasesAsync("{collection_name}").get();
```
```csharp
using Qdrant.Client;
var client = new QdrantClient("localhost", 6334);
await client.ListCollectionAliasesAsync("{collection_name}");
```
### List all aliases
```http
@@ -1369,6 +1503,14 @@ QdrantClient client =
client.listAliasesAsync().get();
```
```csharp
using Qdrant.Client;
var client = new QdrantClient("localhost", 6334);
await client.ListAliasesAsync();
```
### List all collections
```http
@@ -1413,3 +1555,11 @@ QdrantClient client =
client.listCollectionsAsync().get();
```
```csharp
using Qdrant.Client;
var client = new QdrantClient("localhost", 6334);
await client.ListCollectionsAsync();
```
@@ -272,6 +272,20 @@ client
.get();
```
```csharp
using Qdrant.Client;
var client = new QdrantClient("localhost", 6334);
await client.RecommendAsync(
collectionName: "{collection_name}",
positive: new List<ulong> { 100, 231 },
negative: new List<ulong> { 718 },
usingVector: "image",
limit: 10
);
```
Parameter `using` specifies which stored vectors to use for the recommendation.
### Lookup vectors from another collection
@@ -372,6 +386,26 @@ client
.get();
```
```csharp
using Qdrant.Client;
using Qdrant.Client.Grpc;
var client = new QdrantClient("localhost", 6334);
await client.RecommendAsync(
collectionName: "{collection_name}",
positive: new List<ulong> { 100, 231 },
negative: new List<ulong> { 718 },
usingVector: "image",
limit: 10,
lookupFrom: new LookupLocation
{
CollectionName = "{external_collection_name}",
VectorName = "{external_vector_name}",
}
);
```
Vectors are retrieved from the external collection by ids provided in the `positive` and `negative` lists.
These vectors then used to perform the recommendation in the current collection, comparing against the "using" or default vector.
@@ -555,6 +589,45 @@ List<RecommendPoints> recommendQueries =
client.recommendBatchAsync("{collection_name}", recommendQueries, null).get();
```
```csharp
using Qdrant.Client;
using Qdrant.Client.Grpc;
using static Qdrant.Client.Grpc.Conditions;
var client = new QdrantClient("localhost", 6334);
var filter = MatchKeyword("city", "london");
await client.RecommendBatchAsync(
collectionName: "{collection_name}",
recommendSearches: new List<RecommendPoints>
{
new()
{
CollectionName = "{collection_name}",
Positive =
{
new List<PointId> { 100, 231 }
},
Negative = { new List<PointId> { 718 } },
Limit = 3,
Filter = filter,
},
new()
{
CollectionName = "{collection_name}",
Positive =
{
new List<PointId> { 200, 67 }
},
Negative = { new List<PointId> { 300 } },
Limit = 3,
Filter = filter,
}
}
);
```
The result of this API contains one array per recommendation requests.
```json
@@ -764,6 +837,35 @@ client
.get();
```
```csharp
using Qdrant.Client;
using Qdrant.Client.Grpc;
var client = new QdrantClient("localhost", 6334);
await client.DiscoverAsync(
collectionName: "{collection_name}",
target: new TargetVector
{
Single = new VectorExample { Vector = new float[] { 0.2f, 0.1f, 0.9f, 0.7f }, }
},
context: new List<ContextExamplePair>
{
new()
{
Positive = new VectorExample { Id = 100 },
Negative = new VectorExample { Id = 718 }
},
new()
{
Positive = new VectorExample { Id = 200 },
Negative = new VectorExample { Id = 300 }
}
},
limit: 10
);
```
<aside role="status">
Notes about discovery search:
@@ -135,12 +135,25 @@ client
.setFilter(
Filter.newBuilder()
.addAllMust(
List.of(matchKeyword("city", "London"), matchKeyword("color", "Red")))
List.of(matchKeyword("city", "London"), matchKeyword("color", "red")))
.build())
.build())
.get();
```
```csharp
using Qdrant.Client;
using static Qdrant.Client.Grpc.Conditions;
var client = new QdrantClient("localhost", 6334);
// & operator combines two conditions in an AND conjunction(must)
await client.ScrollAsync(
collectionName: "{collection_name}",
filter: MatchKeyword("city", "London") & MatchKeyword("color", "red")
);
```
Filtered points would be:
```json
@@ -230,12 +243,25 @@ client
.setFilter(
Filter.newBuilder()
.addAllShould(
List.of(matchKeyword("city", "London"), matchKeyword("color", "Red")))
List.of(matchKeyword("city", "London"), matchKeyword("color", "red")))
.build())
.build())
.get();
```
```csharp
using Qdrant.Client;
using static Qdrant.Client.Grpc.Conditions;
var client = new QdrantClient("localhost", 6334);
// | operator combines two conditions in an OR disjunction(should)
await client.ScrollAsync(
collectionName: "{collection_name}",
filter: MatchKeyword("city", "London") | MatchKeyword("color", "red")
);
```
Filtered points would be:
```json
@@ -325,12 +351,25 @@ client
.setFilter(
Filter.newBuilder()
.addAllMustNot(
List.of(matchKeyword("city", "London"), matchKeyword("color", "Red")))
List.of(matchKeyword("city", "London"), matchKeyword("color", "red")))
.build())
.build())
.get();
```
```csharp
using Qdrant.Client;
using static Qdrant.Client.Grpc.Conditions;
var client = new QdrantClient("localhost", 6334);
// The ! operator negates the condition(must not)
await client.ScrollAsync(
collectionName: "{collection_name}",
filter: !(MatchKeyword("city", "London") & MatchKeyword("color", "red"))
);
```
Filtered points would be:
```json
@@ -423,12 +462,24 @@ client
.setFilter(
Filter.newBuilder()
.addMust(matchKeyword("city", "London"))
.addMustNot(matchKeyword("color", "Red"))
.addMustNot(matchKeyword("color", "red"))
.build())
.build())
.get();
```
```csharp
using Qdrant.Client;
using static Qdrant.Client.Grpc.Conditions;
var client = new QdrantClient("localhost", 6334);
await client.ScrollAsync(
collectionName: "{collection_name}",
filter: MatchKeyword("city", "London") & !MatchKeyword("color", "red")
);
```
Filtered points would be:
```json
@@ -507,7 +558,7 @@ client
collection_name: "{collection_name}".to_string(),
filter: Some(Filter::must_not([Filter::must([
Condition::matches("city", "London".to_string()),
Condition::matches("color", "Red".to_string()),
Condition::matches("color", "red".to_string()),
])
.into()])),
..Default::default()
@@ -536,13 +587,26 @@ client
.addAllMust(
List.of(
matchKeyword("city", "London"),
matchKeyword("color", "Red")))
matchKeyword("color", "red")))
.build()))
.build())
.build())
.get();
```
```csharp
using Qdrant.Client;
using Qdrant.Client.Grpc;
using static Qdrant.Client.Grpc.Conditions;
var client = new QdrantClient("localhost", 6334);
await client.ScrollAsync(
collectionName: "{collection_name}",
filter: new Filter { MustNot = { MatchKeyword("city", "London") & MatchKeyword("color", "red") } }
);
```
Filtered points would be:
```json
@@ -590,7 +654,13 @@ Condition::matches("color", "red".to_string())
```
```java
matchKeyword("color", "Red");
matchKeyword("color", "red");
```
```csharp
using static Qdrant.Client.Grpc.Conditions;
MatchKeyword("color", "red");
```
For the other types, the match condition will look exactly the same, except for the type used:
@@ -628,6 +698,12 @@ import static io.qdrant.client.ConditionFactory.match;
match("count", 0);
```
```csharp
using static Qdrant.Client.Grpc.Conditions;
Match("count", 0);
```
The simplest kind of condition is one that checks if the stored value equals the given one.
If several values are stored, at least one of them should match the condition.
You can apply it to [keyword](../payload/#keyword), [integer](../payload/#integer) and [bool](../payload/#bool) payloads.
@@ -673,7 +749,13 @@ Condition::matches("color", vec!["black".to_string(), "yellow".to_string()])
```java
import static io.qdrant.client.ConditionFactory.matchKeywords;
matchKeywords("color", List.of("black", "yellow"))
matchKeywords("color", List.of("black", "yellow"));
```
```csharp
using static Qdrant.Client.Grpc.Conditions;
Match("color", ["black", "yellow"]);
```
In this example, the condition will be satisfied if the stored value is either `black` or `yellow`.
@@ -729,6 +811,12 @@ import static io.qdrant.client.ConditionFactory.matchExceptKeywords;
matchExceptKeywords("color", List.of("black", "yellow"));
```
```csharp
using static Qdrant.Client.Grpc.Conditions;
Match("color", ["black", "yellow"]);
```
In this example, the condition will be satisfied if the stored value is neither `black` nor `yellow`.
If the stored value is an array, it should have at least one value not matching any of the given values. E.g. if the stored value is `["black", "green"]`, the condition will be satisfied, because `"green"` does not match `"black"` nor `"yellow"`.
@@ -861,6 +949,16 @@ client
.get();
```
```csharp
using Qdrant.Client;
using Qdrant.Client.Grpc;
using static Qdrant.Client.Grpc.Conditions;
var client = new QdrantClient("localhost", 6334);
await client.ScrollAsync(collectionName: "{collection_name}", filter: MatchKeyword("country.name", "Germany"));
```
You can also search through arrays by projecting inner values using the `[]` syntax.
```http
@@ -956,6 +1054,18 @@ client
.get();
```
```csharp
using Qdrant.Client;
using static Qdrant.Client.Grpc.Conditions;
var client = new QdrantClient("localhost", 6334);
await client.ScrollAsync(
collectionName: "{collection_name}",
filter: Range("country.cities[].population", new Qdrant.Client.Grpc.Range { Gte = 9.0 })
);
```
This query would only output the point with id 2 as only Japan has a city with population greater than 9.0.
And the leaf nested field can also be an array.
@@ -1036,6 +1146,18 @@ client
.get();
```
```csharp
using Qdrant.Client;
using static Qdrant.Client.Grpc.Conditions;
var client = new QdrantClient("localhost", 6334);
await client.ScrollAsync(
collectionName: "{collection_name}",
filter: MatchKeyword("country.cities[].sightseeing", "Germany")
);
```
This query would only output the point with id 2 as only Japan has a city with the "Osaka castke" as part of the sightseeing.
### Nested object filter
@@ -1166,6 +1288,18 @@ client
.get();
```
```csharp
using Qdrant.Client;
using static Qdrant.Client.Grpc.Conditions;
var client = new QdrantClient("localhost", 6334);
await client.ScrollAsync(
collectionName: "{collection_name}",
filter: MatchKeyword("diet[].food", "meat") & Match("diet[].likes", true)
);
```
This happens because both points are matching the two conditions:
- the "t-rex" matches food=meat on `diet[1].food` and likes=true on `diet[1].likes`
@@ -1309,6 +1443,18 @@ client
.get();
```
```csharp
using Qdrant.Client;
using static Qdrant.Client.Grpc.Conditions;
var client = new QdrantClient("localhost", 6334);
await client.ScrollAsync(
collectionName: "{collection_name}",
filter: Nested("diet", MatchKeyword("food", "meat") & Match("likes", true))
);
```
The matching logic is modified to be applied at the level of an array element within the payload.
Nested filters work in the same way as if the nested filter was applied to a single element of the array at a time.
@@ -1459,6 +1605,19 @@ client
.get();
```
```csharp
using Qdrant.Client;
using static Qdrant.Client.Grpc.Conditions;
var client = new QdrantClient("localhost", 6334);
await client.ScrollAsync(
collectionName: "{collection_name}",
filter: Nested("diet", MatchKeyword("food", "meat") & Match("likes", true)) & HasId(1)
);
```
### Full Text Match
*Available as of v0.10.0*
@@ -1506,6 +1665,12 @@ import static io.qdrant.client.ConditionFactory.matchText;
matchText("description", "good cheap");
```
```csharp
using static Qdrant.Client.Grpc.Conditions;
MatchText("description", "good cheap");
```
If the query has several words, then the condition will be satisfied only if all of them are present in the text.
### Range
@@ -1566,6 +1731,12 @@ import io.qdrant.client.grpc.Points.Range;
range("price", Range.newBuilder().setGte(100.0).setLte(450).build());
```
```csharp
using static Qdrant.Client.Grpc.Conditions;
Range("price", new Qdrant.Client.Grpc.Range { Gte = 100.0, Lte = 450 });
```
The `range` condition sets the range of possible values for stored payload values.
If several values are stored, at least one of them should match the condition.
@@ -1652,6 +1823,12 @@ import static io.qdrant.client.ConditionFactory.geoBoundingBox;
geoBoundingBox("location", 52.520711, 13.403683, 52.495862, 13.455868);
```
```csharp
using static Qdrant.Client.Grpc.Conditions;
GeoBoundingBox("location", 52.520711, 13.403683, 52.495862, 13.455868);
```
It matches with `location`s inside a rectangle with the coordinates of the upper left corner in `bottom_right` and the coordinates of the lower right corner in `top_left`.
#### Geo Radius
@@ -1714,6 +1891,12 @@ import static io.qdrant.client.ConditionFactory.geoRadius;
geoRadius("location", 52.520711, 13.403683, 1000.0f);
```
```csharp
using static Qdrant.Client.Grpc.Conditions;
GeoRadius("location", 52.520711, 13.403683, 1000.0f);
```
It matches with `location`s inside a circle with the `center` at the center and a radius of `radius` meters.
If several values are stored, at least one of them should match the condition.
@@ -1951,6 +2134,39 @@ geoPolygon(
.build()));
```
```csharp
using Qdrant.Client.Grpc;
using static Qdrant.Client.Grpc.Conditions;
GeoPolygon(
field: "location",
exterior: new GeoLineString
{
Points =
{
new GeoPoint { Lat = -70.0, Lon = -70.0 },
new GeoPoint { Lat = 60.0, Lon = -70.0 },
new GeoPoint { Lat = 60.0, Lon = 60.0 },
new GeoPoint { Lat = -70.0, Lon = 60.0 },
new GeoPoint { Lat = -70.0, Lon = -70.0 }
}
},
interiors: [
new()
{
Points =
{
new GeoPoint { Lat = -65.0, Lon = -65.0 },
new GeoPoint { Lat = 0.0, Lon = -65.0 },
new GeoPoint { Lat = 0.0, Lon = 0.0 },
new GeoPoint { Lat = -65.0, Lon = 0.0 },
new GeoPoint { Lat = -65.0, Lon = -65.0 }
}
}
]
);
```
A match is considered any point location inside or on the boundaries of the given polygon's exterior but not inside any interiors.
If several location values are stored for a point, then any of them matching will include that point as a candidate in the resultset.
@@ -2012,6 +2228,13 @@ import io.qdrant.client.grpc.Points.ValuesCount;
valuesCount("comments", ValuesCount.newBuilder().setGt(2).build());
```
```csharp
using Qdrant.Client.Grpc;
using static Qdrant.Client.Grpc.Conditions;
ValuesCount("comments", new ValuesCount { Gt = 2 });
```
The result would be:
```json
@@ -2057,6 +2280,13 @@ import static io.qdrant.client.ConditionFactory.isEmpty;
isEmpty("reports");
```
```csharp
using Qdrant.Client.Grpc;
using static Qdrant.Client.Grpc.Conditions;
IsEmpty("reports");
```
This condition will match all records where the field `reports` either does not exist, or has `null` or `[]` value.
<aside role="status">The <b>IsEmpty</b> is often useful together with the logical negation <b>must_not</b>. In this case all non-empty values will be selected.</aside>
@@ -2098,6 +2328,13 @@ import static io.qdrant.client.ConditionFactory.isNull;
isNull("reports");
```
```csharp
using Qdrant.Client.Grpc;
using static Qdrant.Client.Grpc.Conditions;
IsNull("reports");
```
This condition will match all records where the field `reports` exists and has `NULL` value.
@@ -2174,6 +2411,15 @@ client
.get();
```
```csharp
using Qdrant.Client;
using static Qdrant.Client.Grpc.Conditions;
var client = new QdrantClient("localhost", 6334);
await client.ScrollAsync(collectionName: "{collection_name}", filter: HasId([1, 3, 5, 7, 9, 11]));
```
Filtered points would be:
```json
@@ -92,6 +92,14 @@ client
.get();
```
```csharp
using Qdrant.Client;
var client = new QdrantClient("localhost", 6334);
await client.CreatePayloadIndexAsync(collectionName: "{collection_name}", fieldName: "name_of_the_field_to_index");
```
Available field types are:
* `keyword` - for [keyword](../payload/#keyword) payload, affects [Match](../filtering/#match) filtering conditions.
@@ -216,7 +224,7 @@ client
.setTextIndexParams(
TextIndexParams.newBuilder()
.setTokenizer(TokenizerType.Word)
.setMaxTokenLen(2)
.setMinTokenLen(2)
.setMaxTokenLen(10)
.setLowercase(true)
.build())
@@ -227,6 +235,29 @@ client
.get();
```
```csharp
using Qdrant.Client;
using Qdrant.Client.Grpc;
var client = new QdrantClient("localhost", 6334);
await client.CreatePayloadIndexAsync(
collectionName: "{collection_name}",
fieldName: "name_of_the_field_to_index",
schemaType: PayloadSchemaType.Text,
indexParams: new PayloadIndexParams
{
TextIndexParams = new TextIndexParams
{
Tokenizer = TokenizerType.Word,
MinTokenLen = 2,
MaxTokenLen = 10,
Lowercase = true
}
}
);
```
Available tokenizers are:
* `word` - splits the string into words, separated by spaces, punctuation marks, and special characters.
@@ -319,6 +319,45 @@ client
.get();
```
```csharp
using Qdrant.Client;
using Qdrant.Client.Grpc;
var client = new QdrantClient("localhost", 6334);
await client.UpsertAsync(
collectionName: "{collection_name}",
points: new List<PointStruct>
{
new PointStruct
{
Id = 1,
Vectors = new[] { 0.05f, 0.61f, 0.76f, 0.74f },
Payload = { ["city"] = "Berlin", ["price"] = 1.99 }
},
new PointStruct
{
Id = 2,
Vectors = new[] { 0.19f, 0.81f, 0.75f, 0.11f },
Payload = { ["city"] = new[] { "Berlin", "London" } }
},
new PointStruct
{
Id = 3,
Vectors = new[] { 0.36f, 0.55f, 0.47f, 0.94f },
Payload =
{
["city"] = new[] { "Berlin", "Moscow" },
["price"] = new Value
{
ListValue = new ListValue { Values = { new Value[] { 1.99, 2.99 } } }
}
}
}
}
);
```
## Update payload
### Set payload
@@ -405,6 +444,19 @@ client
.get();
```
```csharp
using Qdrant.Client;
using Qdrant.Client.Grpc;
var client = new QdrantClient("localhost", 6334);
await client.SetPayloadAsync(
collectionName: "{collection_name}",
payload: new Dictionary<string, Value> { { "property1", "string" }, { "property2", "string" } },
ids: new ulong[] { 0, 3, 10 }
);
```
You don't need to know the ids of the points you want to modify. The alternative
is to use filters.
@@ -508,6 +560,20 @@ client
.get();
```
```csharp
using Qdrant.Client;
using Qdrant.Client.Grpc;
using static Qdrant.Client.Grpc.Conditions;
var client = new QdrantClient("localhost", 6334);
await client.SetPayloadAsync(
collectionName: "{collection_name}",
payload: new Dictionary<string, Value> { { "property1", "string" }, { "property2", "string" } },
filter: MatchKeyword("color", "red")
);
```
### Overwrite payload
Fully replace any existing payload with the given one.
@@ -591,6 +657,19 @@ client
.get();
```
```csharp
using Qdrant.Client;
using Qdrant.Client.Grpc;
var client = new QdrantClient("localhost", 6334);
await client.OverwritePayloadAsync(
collectionName: "{collection_name}",
payload: new Dictionary<string, Value> { { "property1", "string" }, { "property2", "string" } },
ids: new ulong[] { 0, 3, 10 }
);
```
Like [set payload](#set-payload), you don't need to know the ids of the points
you want to modify. The alternative is to use filters.
@@ -651,6 +730,14 @@ client
.get();
```
```csharp
using Qdrant.Client;
var client = new QdrantClient("localhost", 6334);
await client.ClearPayloadAsync(collectionName: "{collection_name}", ids: new ulong[] { 0, 3, 100 });
```
<aside role="status">
You can also use <code>models.FilterSelector</code> to remove the points matching given filter criteria, instead of providing the ids.
</aside>
@@ -720,6 +807,19 @@ client
.get();
```
```csharp
using Qdrant.Client;
var client = new QdrantClient("localhost", 6334);
await client.DeletePayloadAsync(
collectionName: "{collection_name}",
keys: ["color", "price"],
ids: new ulong[] { 0, 3, 100 }
);
```
Alternatively, you can use filters to delete payload keys from the points.
```http
@@ -806,6 +906,19 @@ client
.get();
```
```csharp
using Qdrant.Client;
using static Qdrant.Client.Grpc.Conditions;
var client = new QdrantClient("localhost", 6334);
await client.DeletePayloadAsync(
collectionName: "{collection_name}",
keys: ["color", "price"],
filter: MatchKeyword("color", "red")
);
```
## Payload indexing
To search more efficiently with filters, Qdrant allows you to create indexes for payload fields by specifying the name and type of field it is intended to be.
@@ -871,6 +984,17 @@ client.createPayloadIndexAsync(
null);
```
```csharp
using Qdrant.Client;
var client = new QdrantClient("localhost", 6334);
await client.CreatePayloadIndexAsync(
collectionName: "{collection_name}",
fieldName: "name_of_the_field_to_index"
);
```
The index usage flag is displayed in the payload schema with the [collection info API](https://qdrant.github.io/qdrant/redoc/index.html#operation/get_collection).
Payload schema example:
@@ -171,6 +171,26 @@ client
.get();
```
```csharp
using Qdrant.Client;
using Qdrant.Client.Grpc;
var client = new QdrantClient("localhost", 6334);
await client.UpsertAsync(
collectionName: "{collection_name}",
points: new List<PointStruct>
{
new()
{
Id = Guid.Parse("5c56c793-69f3-4fbf-87e6-c4bf54c28c26"),
Vectors = new[] { 0.05f, 0.61f, 0.76f, 0.74f },
Payload = { ["city"] = "red" }
}
}
);
```
and
```http
@@ -264,6 +284,27 @@ client
.get();
```
```csharp
using Qdrant.Client;
using Qdrant.Client.Grpc;
var client = new QdrantClient("localhost", 6334);
await client.UpsertAsync(
collectionName: "{collection_name}",
points: new List<PointStruct>
{
new()
{
Id = 1,
Vectors = new[] { 0.05f, 0.61f, 0.76f, 0.74f },
Payload = { ["city"] = "red" }
}
}
);
```
are both possible.
## Upload points
@@ -448,6 +489,74 @@ client
.await?;
```
```java
import java.util.List;
import java.util.Map;
import static io.qdrant.client.PointIdFactory.id;
import static io.qdrant.client.ValueFactory.value;
import static io.qdrant.client.VectorsFactory.vectors;
import io.qdrant.client.QdrantClient;
import io.qdrant.client.QdrantGrpcClient;
import io.qdrant.client.grpc.Points.PointStruct;
QdrantClient client =
new QdrantClient(QdrantGrpcClient.newBuilder("localhost", 6334, false).build());
client
.upsertAsync(
"{collection_name}",
List.of(
PointStruct.newBuilder()
.setId(id(1))
.setVectors(vectors(0.9f, 0.1f, 0.1f))
.putAllPayload(Map.of("color", value("red")))
.build(),
PointStruct.newBuilder()
.setId(id(2))
.setVectors(vectors(0.1f, 0.9f, 0.1f))
.putAllPayload(Map.of("color", value("green")))
.build(),
PointStruct.newBuilder()
.setId(id(3))
.setVectors(vectors(0.1f, 0.1f, 0.9f))
.putAllPayload(Map.of("color", value("blue")))
.build()))
.get();
```
```csharp
using Qdrant.Client;
using Qdrant.Client.Grpc;
var client = new QdrantClient("localhost", 6334);
await client.UpsertAsync(
collectionName: "{collection_name}",
points: new List<PointStruct>
{
new()
{
Id = 1,
Vectors = new[] { 0.9f, 0.1f, 0.1f },
Payload = { ["city"] = "red" }
},
new()
{
Id = 2,
Vectors = new[] { 0.1f, 0.9f, 0.1f },
Payload = { ["city"] = "green" }
},
new()
{
Id = 3,
Vectors = new[] { 0.1f, 0.1f, 0.9f },
Payload = { ["city"] = "blue" }
}
}
);
```
The Python client has additional features for loading points, which include:
@@ -663,6 +772,38 @@ client
.get();
```
```csharp
using Qdrant.Client;
using Qdrant.Client.Grpc;
var client = new QdrantClient("localhost", 6334);
await client.UpsertAsync(
collectionName: "{collection_name}",
points: new List<PointStruct>
{
new()
{
Id = 1,
Vectors = new Dictionary<string, float[]>
{
["image"] = [0.9f, 0.1f, 0.1f, 0.2f],
["text"] = [0.4f, 0.7f, 0.1f, 0.8f, 0.1f, 0.1f, 0.9f, 0.2f]
}
},
new()
{
Id = 2,
Vectors = new Dictionary<string, float[]>
{
["image"] = [0.2f, 0.1f, 0.3f, 0.9f],
["text"] = [0.5f, 0.2f, 0.7f, 0.4f, 0.7f, 0.2f, 0.3f, 0.9f]
}
}
}
);
```
*Available as of v1.2.0*
Named vectors are optional. When uploading points, some vectors may be omitted.
@@ -872,6 +1013,33 @@ client
.get();
```
```csharp
using Qdrant.Client;
using Qdrant.Client.Grpc;
var client = new QdrantClient("localhost", 6334);
await client.UpsertAsync(
collectionName: "{collection_name}",
points: new List<PointStruct>
{
new()
{
Id = 1,
Vectors = new Dictionary<string, Vector> { ["text"] = ([1.0f, 2.0f], [6, 7]) }
},
new()
{
Id = 2,
Vectors = new Dictionary<string, Vector>
{
["text"] = ([0.1f, 0.2f, 0.3f, 0.4f, 0.5f], [1, 2, 3, 4, 5])
}
}
}
);
```
## Modify points
To change a point, you can modify its vectors or its payload. There are several
@@ -1002,6 +1170,25 @@ client
.get();
```
```csharp
using Qdrant.Client;
using Qdrant.Client.Grpc;
var client = new QdrantClient("localhost", 6334);
await client.UpdateVectorsAsync(
collectionName: "{collection_name}",
points: new List<PointVectors>
{
new() { Id = 1, Vectors = ("image", new float[] { 0.1f, 0.2f, 0.3f, 0.4f }) },
new()
{
Id = 2,
Vectors = ("text", new float[] { 0.9f, 0.8f, 0.7f, 0.6f, 0.5f, 0.4f, 0.3f, 0.2f })
}
}
);
```
To update points and replace all of its vectors, see [uploading
points](#upload-points).
@@ -1132,6 +1319,14 @@ import static io.qdrant.client.PointIdFactory.id;
client.deleteAsync("{collection_name}", List.of(id(0), id(3), id(100)));
```
```csharp
using Qdrant.Client;
var client = new QdrantClient("localhost", 6334);
await client.DeleteAsync(collectionName: "{collection_name}", ids: [0, 3, 100]);
```
Alternative way to specify which points to remove is to use filter.
```http
@@ -1212,6 +1407,15 @@ client
.get();
```
```csharp
using Qdrant.Client;
using static Qdrant.Client.Grpc.Conditions;
var client = new QdrantClient("localhost", 6334);
await client.DeleteAsync(collectionName: "{collection_name}", filter: MatchKeyword("color", "red"));
```
This example removes all points with `{ "color": "red" }` from the collection.
## Retrieve points
@@ -1263,6 +1467,19 @@ client
.get();
```
```csharp
using Qdrant.Client;
var client = new QdrantClient("localhost", 6334);
await client.RetrieveAsync(
collectionName: "{collection_name}",
ids: [0, 30, 100],
withPayload: false,
withVectors: false
);
```
This method has additional parameters `with_vectors` and `with_payload`.
Using these parameters, you can select parts of the point you want as a result.
Excluding helps you not to waste traffic transmitting useless data.
@@ -1375,6 +1592,20 @@ client
.get();
```
```csharp
using Qdrant.Client;
using static Qdrant.Client.Grpc.Conditions;
var client = new QdrantClient("localhost", 6334);
await client.ScrollAsync(
collectionName: "{collection_name}",
filter: MatchKeyword("color", "red"),
limit: 1,
payloadSelector: true
);
```
Returns all point with `color` = `red`.
```json
@@ -1495,6 +1726,19 @@ client
.get();
```
```csharp
using Qdrant.Client;
using static Qdrant.Client.Grpc.Conditions;
var client = new QdrantClient("localhost", 6334);
await client.CountAsync(
collectionName: "{collection_name}",
filter: MatchKeyword("color", "red"),
exact: true
);
```
Returns number of counts matching given filtering conditions:
```json
@@ -184,6 +184,22 @@ client
.get();
```
```csharp
using Qdrant.Client;
using Qdrant.Client.Grpc;
using static Qdrant.Client.Grpc.Conditions;
var client = new QdrantClient("localhost", 6334);
await client.SearchAsync(
collectionName: "{collection_name}",
vector: new float[] { 0.2f, 0.1f, 0.9f, 0.7f },
filter: MatchKeyword("city", "London"),
searchParams: new SearchParams { Exact = false, HnswEf = 128 },
limit: 3
);
```
In this example, we are looking for vectors similar to vector `[0.2, 0.1, 0.9, 0.7]`.
Parameter `limit` (or its alias - `top`) specifies the amount of most similar results we would like to retrieve.
@@ -296,6 +312,19 @@ client
.get();
```
```csharp
using Qdrant.Client;
var client = new QdrantClient("localhost", 6334);
await client.SearchAsync(
collectionName: "{collection_name}",
vector: new float[] { 0.2f, 0.1f, 0.9f, 0.7f },
vectorName: "image",
limit: 3
);
```
Search is processing only among vectors with the same name.
*Available as of v1.7.0*
@@ -406,6 +435,20 @@ client
.get();
```
```csharp
using Qdrant.Client;
var client = new QdrantClient("localhost", 6334);
await client.SearchAsync(
collectionName: "{collection_name}",
vector: new float[] { 2.0f, 1.0f },
vectorName: "text",
limit: 3,
sparseIndices: new uint[] { 1, 7 }
);
```
### Filtering results by score
In addition to payload filtering, it might be useful to filter out results with a low similarity score.
@@ -491,6 +534,20 @@ client
.get();
```
```csharp
using Qdrant.Client;
var client = new QdrantClient("localhost", 6334);
await client.SearchAsync(
collectionName: "{collection_name}",
vector: new float[] { 0.2f, 0.1f, 0.9f, 0.7f },
payloadSelector: true,
vectorsSelector: true,
limit: 3
);
```
You can use `with_payload` to scope to or filter a specific payload subset.
You can even specify an array of items to include, such as `city`,
`village`, and `town`:
@@ -566,6 +623,26 @@ client
.get();
```
```csharp
using Qdrant.Client;
using Qdrant.Client.Grpc;
var client = new QdrantClient("localhost", 6334);
await client.SearchAsync(
collectionName: "{collection_name}",
vector: new float[] { 0.2f, 0.1f, 0.9f, 0.7f },
payloadSelector: new WithPayloadSelector
{
Include = new PayloadIncludeSelector
{
Fields = { new string[] { "city", "village", "town" } }
}
},
limit: 3
);
```
Or use `include` or `exclude` explicitly. For example, to exclude `city`:
```http
@@ -655,6 +732,23 @@ client
.get();
```
```csharp
using Qdrant.Client;
using Qdrant.Client.Grpc;
var client = new QdrantClient("localhost", 6334);
await client.SearchAsync(
collectionName: "{collection_name}",
vector: new float[] { 0.2f, 0.1f, 0.9f, 0.7f },
payloadSelector: new WithPayloadSelector
{
Exclude = new PayloadExcludeSelector { Fields = { new string[] { "city" } } }
},
limit: 3
);
```
It is possible to target nested fields using a dot notation:
- `payload.nested_field` - for a nested field
- `payload.nested_array[].sub_field` - for projecting nested fields within an array
@@ -838,6 +932,34 @@ List<SearchPoints> searches =
client.searchBatchAsync("{collection_name}", searches, null).get();
```
```csharp
using Qdrant.Client;
using Qdrant.Client.Grpc;
using static Qdrant.Client.Grpc.Conditions;
var client = new QdrantClient("localhost", 6334);
var filter = MatchKeyword("city", "London");
var searches = new List<SearchPoints>
{
new()
{
Vector = { new float[] { 0.2f, 0.1f, 0.9f, 0.7f } },
Filter = filter,
Limit = 3
},
new()
{
Vector = { new float[] { 0.5f, 0.3f, 0.2f, 0.3f } },
Filter = filter,
Limit = 3
}
};
await client.SearchBatchAsync(collectionName: "{collection_name}", searches: searches);
```
The result of this API contains one array per search requests.
```json
@@ -951,6 +1073,21 @@ client
.get();
```
```csharp
using Qdrant.Client;
var client = new QdrantClient("localhost", 6334);
await client.SearchAsync(
"{collection_name}",
new float[] { 0.2f, 0.1f, 0.9f, 0.7f },
payloadSelector: true,
vectorsSelector: true,
limit: 10,
offset: 100
);
```
Is equivalent to retrieving the 11th page with 10 records per page.
<aside role="alert">Large offset values may cause performance issues</aside>
@@ -1097,6 +1234,20 @@ client
.get();
```
```csharp
using Qdrant.Client;
var client = new QdrantClient("localhost", 6334);
await client.SearchGroupsAsync(
collectionName: "{collection_name}",
vector: new float[] { 1.1f },
groupBy: "document_id",
limit: 4,
groupSize: 2
);
```
The output of a ***groups*** call looks like this:
```json
@@ -1274,6 +1425,30 @@ client
.get();
```
```csharp
using Qdrant.Client;
using Qdrant.Client.Grpc;
var client = new QdrantClient("localhost", 6334);
await client.SearchGroupsAsync(
collectionName: "{collection_name}",
vector: new float[] { 1.0f },
groupBy: "document_id",
limit: 2,
groupSize: 2,
withLookup: new WithLookup
{
Collection = "documents",
WithPayload = new WithPayloadSelector
{
Include = new PayloadIncludeSelector { Fields = { new string[] { "title", "text" } } }
},
WithVectors = false
}
);
```
For the `with_lookup` parameter, you can also use the shorthand `with_lookup="documents"` to bring the whole payload and vector(s) without explicitly specifying it.
The looked up result will show up under `lookup` in each group.
@@ -81,6 +81,14 @@ QdrantClient client =
client.createSnapshotAsync("{collection_name}").get();
```
```csharp
using Qdrant.Client;
var client = new QdrantClient("localhost", 6334);
await client.CreateSnapshotAsync("{collection_name}");
```
This is a synchronous operation for which a `tar` archive file will be generated into the `snapshot_path`.
### Delete snapshot
@@ -127,6 +135,14 @@ QdrantClient client =
client.deleteSnapshotAsync("{collection_name}", "{snapshot_name}").get();
```
```csharp
using Qdrant.Client;
var client = new QdrantClient("localhost", 6334);
await client.DeleteSnapshotAsync(collectionName: "{collection_name}", snapshotName: "{snapshot_name}");
```
## List snapshot
List of snapshots for a collection:
@@ -169,6 +185,14 @@ QdrantClient client =
client.listSnapshotAsync("{collection_name}").get();
```
```csharp
using Qdrant.Client;
var client = new QdrantClient("localhost", 6334);
await client.ListSnapshotsAsync("{collection_name}");
```
## Retrieve snapshot
<aside role="status">Only available through the REST API for the time being.</aside>
@@ -368,6 +392,14 @@ QdrantClient client =
client.createFullSnapshotAsync().get();
```
```csharp
using Qdrant.Client;
var client = new QdrantClient("localhost", 6334);
await client.CreateFullSnapshotAsync();
```
### Delete full storage snapshot
*Available as of v1.0.0*
@@ -410,6 +442,14 @@ QdrantClient client =
client.deleteFullSnapshotAsync("{snapshot_name}").get();
```
```csharp
using Qdrant.Client;
var client = new QdrantClient("localhost", 6334);
await client.DeleteFullSnapshotAsync("{snapshot_name}");
```
### List full storage snapshots
```http
@@ -450,6 +490,14 @@ QdrantClient client =
client.listFullSnapshotAsync().get();
```
```csharp
using Qdrant.Client;
var client = new QdrantClient("localhost", 6334);
await client.ListFullSnapshotsAsync();
```
### Download full storage snapshot
<aside role="status">Only available through the REST API for the time being.</aside>
@@ -124,6 +124,23 @@ client
.get();
```
```csharp
using Qdrant.Client;
using Qdrant.Client.Grpc;
var client = new QdrantClient("localhost", 6334);
await client.CreateCollectionAsync(
"{collection_name}",
new VectorParams
{
Size = 768,
Distance = Distance.Cosine,
OnDisk = true
}
);
```
This will create a collection with all vectors immediately stored in memmap storage.
This is the recommended way, in case your Qdrant instance operates with fast disks and you are working with large collections.
@@ -236,6 +253,19 @@ client
.get();
```
```csharp
using Qdrant.Client;
using Qdrant.Client.Grpc;
var client = new QdrantClient("localhost", 6334);
await client.CreateCollectionAsync(
collectionName: "{collection_name}",
vectorsConfig: new VectorParams { Size = 768, Distance = Distance.Cosine },
optimizersConfig: new OptimizersConfigDiff { MemmapThreshold = 20000 }
);
```
The rule of thumb to set the memmap threshold parameter is simple:
- if you have a balanced use scenario - set memmap threshold the same as `indexing_threshold` (default is 20000). In this case the optimizer will not make any extra runs and will optimize all thresholds at once.
@@ -358,6 +388,20 @@ client
.get();
```
```csharp
using Qdrant.Client;
using Qdrant.Client.Grpc;
var client = new QdrantClient("localhost", 6334);
await client.CreateCollectionAsync(
collectionName: "{collection_name}",
vectorsConfig: new VectorParams { Size = 768, Distance = Distance.Cosine },
optimizersConfig: new OptimizersConfigDiff { MemmapThreshold = 20000 },
hnswConfig: new HnswConfigDiff { OnDisk = true }
);
```
## Payload storage
Qdrant supports two types of payload storages: InMemory and OnDisk.
@@ -6,7 +6,7 @@ aliases:
---
# Quickstart
In this short example, you will use the Python Client to create a Collection, load data into it and run a basic search query.
In this short example, you will use the Python Client to create a Collection, load data into it and run a basic search query.
<aside role="status">Before you start, please make sure Docker is installed and running on your system.</aside>
@@ -26,14 +26,15 @@ docker run -p 6333:6333 -p 6334:6334 \
qdrant/qdrant
```
Under the default configuration all data will be stored in the `./qdrant_storage` directory. This will also be the only directory that both the Container and the host machine can both see.
Under the default configuration all data will be stored in the `./qdrant_storage` directory. This will also be the only directory that both the Container and the host machine can both see.
Qdrant is now accessible:
- REST API: [localhost:6333](http://localhost:6333)
- Web UI: [localhost:6333/dashboard](http://localhost:6333/dashboard)
- GRPC API: [localhost:6334](http://localhost:6334)
## Initialize the client
## Initialize the client
```python
from qdrant_client import QdrantClient
@@ -58,15 +59,23 @@ let client = QdrantClient::from_url("http://localhost:6334").build()?;
import io.qdrant.client.QdrantClient;
import io.qdrant.client.QdrantGrpcClient;
// The Java client uses Qdrant's GRPC interface
QdrantClient client = new QdrantClient(
QdrantGrpcClient.newBuilder("localhost", 6334, false).build());
```
```csharp
using Qdrant.Client;
// The C# client uses Qdrant's GRPC interface
var client = new QdrantClient("localhost", 6334);
```
<aside role="status">By default, Qdrant starts with no encryption or authentication . This means anyone with network access to your machine can access your Qdrant container instance. Please read <a href="https://qdrant.tech/documentation/security/">Security</a> carefully for details on how to secure your instance.</aside>
## Create a collection
You will be storing all of your vector data in a Qdrant collection. Let's call it `test_collection`. This collection will be using a dot product distance metric to compare vectors.
You will be storing all of your vector data in a Qdrant collection. Let's call it `test_collection`. This collection will be using a dot product distance metric to compare vectors.
```python
from qdrant_client.http.models import Distance, VectorParams
@@ -109,6 +118,15 @@ client.createCollectionAsync("test_collection",
VectorParams.newBuilder().setDistance(Distance.Dot).setSize(4).build()).get();
```
```csharp
using Qdrant.Client.Grpc;
await client.CreateCollectionAsync(
collectionName: "test_collection",
vectorsConfig: new VectorParams { Size = 4, Distance = Distance.Dot }
);
```
<aside role="status">TypeScript, Rust examples use async/await syntax, so should be used in an async block.</aside>
<aside role="status">Java examples are enclosed within a try/catch block.</aside>
@@ -220,6 +238,38 @@ UpdateResult operationInfo =
System.out.println(operationInfo);
```
```csharp
using Qdrant.Client.Grpc;
var operationInfo = await client.UpsertAsync(
collectionName: "test_collection",
points: new List<PointStruct>
{
new()
{
Id = 1,
Vectors = new float[] { 0.05f, 0.61f, 0.76f, 0.74f },
Payload = { ["city"] = "Berlin" }
},
new()
{
Id = 2,
Vectors = new float[] { 0.19f, 0.81f, 0.75f, 0.11f },
Payload = { ["city"] = "London" }
},
new()
{
Id = 3,
Vectors = new float[] { 0.36f, 0.55f, 0.47f, 0.94f },
Payload = { ["city"] = "Moscow" }
},
// Truncated
}
);
Console.WriteLine(operationInfo);
```
**Response:**
```python
@@ -245,7 +295,12 @@ operation_id: 0
status: Completed
```
```csharp
{ "operationId": "0", "status": "Completed" }
```
## Run a query
Let's ask a basic question - Which of our stored vectors are most similar to the query vector `[0.2, 0.1, 0.9, 0.7]`?
```python
@@ -303,6 +358,17 @@ List<ScoredPoint> searchResult =
System.out.println(searchResult);
```
```csharp
var searchResult = await client.SearchAsync(
collectionName: "test_collection",
vector: new float[] { 0.2f, 0.1f, 0.9f, 0.7f },
limit: 3,
payloadSelector: true
);
Console.WriteLine(searchResult);
```
**Response:**
```python
@@ -409,6 +475,47 @@ version: 1
]
```
```csharp
[
{
"id": {
"num": "4"
},
"payload": {
"city": {
"stringValue": "New York"
}
},
"score": 1.362,
"version": "7"
},
{
"id": {
"num": "1"
},
"payload": {
"city": {
"stringValue": "Berlin"
}
},
"score": 1.273,
"version": "7"
},
{
"id": {
"num": "3"
},
"payload": {
"city": {
"stringValue": "Moscow"
}
},
"score": 1.208,
"version": "7"
}
]
```
The results are returned in decreasing similarity order. Note that payload and vector data is missing in these results by default.
See [payload and vector in the result](../concepts/search#payload-and-vector-in-the-result) on how to enable it.
@@ -482,6 +589,20 @@ List<ScoredPoint> searchResult =
System.out.println(searchResult);
```
```csharp
using static Qdrant.Client.Grpc.Conditions;
var searchResult = await client.SearchAsync(
collectionName: "test_collection",
vector: new float[] { 0.2f, 0.1f, 0.9f, 0.7f },
filter: MatchKeyword("city", "London"),
limit: 3,
payloadSelector: true
);
Console.WriteLine(searchResult);
```
**Response:**
```python
@@ -546,14 +667,31 @@ version: 1
]
```
```csharp
[
{
"id": {
"num": "2"
},
"payload": {
"city": {
"stringValue": "London"
}
},
"score": 0.871,
"version": "7"
}
]
```
<aside role="status">To make filtered search fast on real datasets, we highly recommend to create <a href="../concepts/indexing/#payload-index">payload indexes</a>!</aside>
You have just conducted vector search. You loaded vectors into a database and queried the database with a vector of your own. Qdrant found the closest results and presented you with a similarity score.
## Next steps
Now you know how Qdrant works. Getting started with [Qdrant Cloud](../cloud/quickstart-cloud/) is just as easy. [Create an account](https://qdrant.to/cloud) and use our SaaS completely free. We will take care of infrastructure maintenance and software updates.
Now you know how Qdrant works. Getting started with [Qdrant Cloud](../cloud/quickstart-cloud/) is just as easy. [Create an account](https://qdrant.to/cloud) and use our SaaS completely free. We will take care of infrastructure maintenance and software updates.
To move onto some more complex examples of vector search, read our [Tutorials](../tutorials/) and create your own app with the help of our [Examples](../examples/).
To move onto some more complex examples of vector search, read our [Tutorials](../tutorials/) and create your own app with the help of our [Examples](../examples/).
**Note:** There is another way of running Qdrant locally. If you are a Python developer, we recommend that you try Local Mode in [Qdrant Client](https://github.com/qdrant/qdrant-client), as it only takes a few moments to get setup.