docs: Query API snippets with Python (#1095)

Co-authored-by: generall <andrey@vasnetsov.com>
This commit is contained in:
Anush
2024-08-23 22:48:27 +05:30
committed by GitHub
co-authored by generall
parent 4821e18664
commit e9fa9be0a4
17 changed files with 203 additions and 195 deletions
@@ -43,11 +43,15 @@ from qdrant_client import QdrantClient, models
client = QdrantClient(url="http://localhost:6333")
client.recommend(
client.query_points(
collection_name="{collection_name}",
positive=[100, 231],
negative=[718, [0.2, 0.3, 0.4, 0.5]],
strategy=models.RecommendStrategy.AVERAGE_VECTOR,
query=models.RecommendQuery(
recommend=models.RecommendInput(
positive=[100, 231],
negative=[718, [0.2, 0.3, 0.4, 0.5]],
strategy=models.RecommendStrategy.AVERAGE_VECTOR,
)
),
query_filter=models.Filter(
must=[
models.FieldCondition(
@@ -245,10 +249,14 @@ POST /collections/{collection_name}/points/query
```
```python
client.recommend(
client.query_points(
collection_name="{collection_name}",
positive=[100, 231],
negative=[718],
query=models.RecommendQuery(
recommend=models.RecommendInput(
positive=[100, 231],
negative=[718],
)
),
using="image",
limit=10,
)
@@ -350,15 +358,18 @@ POST /collections/{collection_name}/points/query
```
```python
client.recommend(
client.query_points(
collection_name="{collection_name}",
positive=[100, 231],
negative=[718],
query=models.RecommendQuery(
recommend=models.RecommendInput(
positive=[100, 231],
negative=[718],
)
),
using="image",
limit=10,
lookup_from=models.LookupLocation(
collection="{external_collection_name}",
vector="{external_vector_name}"
collection="{external_collection_name}", vector="{external_vector_name}"
),
)
```
@@ -520,13 +531,25 @@ filter_ = models.Filter(
)
recommend_queries = [
models.RecommendRequest(
positive=[100, 231], negative=[718], filter=filter_, limit=3
models.QueryRequest(
query=models.RecommendQuery(
recommend=models.RecommendInput(positive=[100, 231], negative=[718])
),
filter=filter_,
limit=3,
),
models.QueryRequest(
query=models.RecommendQuery(
recommend=models.RecommendInput(positive=[200, 67], negative=[300])
),
filter=filter_,
limit=3,
),
models.RecommendRequest(positive=[200, 67], negative=[300], filter=filter_, limit=3),
]
client.recommend_batch(collection_name="{collection_name}", requests=recommend_queries)
client.query_batch_points(
collection_name="{collection_name}", requests=recommend_queries
)
```
```typescript
@@ -776,18 +799,22 @@ from qdrant_client import QdrantClient, models
client = QdrantClient(url="http://localhost:6333")
discover_queries = [
models.DiscoverRequest(
target=[0.2, 0.1, 0.9, 0.7],
context=[
models.ContextExamplePair(
positive=100,
negative=718,
),
models.ContextExamplePair(
positive=200,
negative=300,
),
],
models.QueryRequest(
query=models.DiscoverQuery(
discover=models.DiscoverInput(
target=[0.2, 0.1, 0.9, 0.7],
context=[
models.ContextPair(
positive=100,
negative=718,
),
models.ContextPair(
positive=200,
negative=300,
),
],
)
),
limit=10,
),
]
@@ -948,17 +975,19 @@ from qdrant_client import QdrantClient, models
client = QdrantClient(url="http://localhost:6333")
discover_queries = [
models.DiscoverRequest(
context=[
models.ContextExamplePair(
positive=100,
negative=718,
),
models.ContextExamplePair(
positive=200,
negative=300,
),
],
models.QueryRequest(
query=models.ContextQuery(
context=[
models.ContextPair(
positive=100,
negative=718,
),
models.ContextPair(
positive=200,
negative=300,
),
],
),
limit=10,
),
]
@@ -11,7 +11,6 @@ Searching for the nearest vectors is at the core of many representational learni
Modern neural networks are trained to transform objects into vectors so that objects close in the real world appear close in vector space.
It could be, for example, texts with similar meanings, visually similar pictures, or songs of the same genre.
{{< figure src="/docs/encoders.png" caption="This is how vector similarity works" width="70%" >}}
## Query API
@@ -36,7 +35,6 @@ Depending on the `query` parameter, Qdrant might prefer different strategies for
| [Multi-Stage Search](../hybrid-queries/#multi-stage-queries) | Optimize performance for large embeddings |
| [Random Sampling](#random-sampling) | Get random points from the collection |
**Nearest Neighbors Search**
```http
@@ -100,8 +98,8 @@ using Qdrant.Client;
var client = new QdrantClient("localhost", 6334);
await client.QueryAsync(
collectionName: "{collection_name}",
query: new float[] { 0.2f, 0.1f, 0.9f, 0.7f }
collectionName: "{collection_name}",
query: new float[] { 0.2f, 0.1f, 0.9f, 0.7f }
);
```
@@ -168,8 +166,8 @@ using Qdrant.Client;
var client = new QdrantClient("localhost", 6334);
await client.QueryAsync(
collectionName: "{collection_name}",
query: Guid.Parse("43cf51e2-8777-4f52-bc74-c2cbde0c8b04")
collectionName: "{collection_name}",
query: Guid.Parse("43cf51e2-8777-4f52-bc74-c2cbde0c8b04")
);
```
@@ -181,10 +179,10 @@ The choice of metric depends on the vectors obtained and, in particular, on the
Qdrant supports these most popular types of metrics:
* Dot product: `Dot` - https://en.wikipedia.org/wiki/Dot_product
* Cosine similarity: `Cosine` - https://en.wikipedia.org/wiki/Cosine_similarity
* Euclidean distance: `Euclid` - https://en.wikipedia.org/wiki/Euclidean_distance
* Manhattan distance: `Manhattan`* - https://en.wikipedia.org/wiki/Taxicab_geometry <i><sup>*Available as of v1.7</sup></i>
* Dot product: `Dot` - <https://en.wikipedia.org/wiki/Dot_product>
* Cosine similarity: `Cosine` - <https://en.wikipedia.org/wiki/Cosine_similarity>
* Euclidean distance: `Euclid` - <https://en.wikipedia.org/wiki/Euclidean_distance>
* Manhattan distance: `Manhattan`*- <https://en.wikipedia.org/wiki/Taxicab_geometry> <i><sup>*Available as of v1.7</sup></i>
The most typical metric used in similarity learning models is the cosine metric.
@@ -233,8 +231,9 @@ from qdrant_client import QdrantClient, models
client = QdrantClient(url="http://localhost:6333")
client.search(
client.query_points(
collection_name="{collection_name}",
query=[0.2, 0.1, 0.9, 0.7],
query_filter=models.Filter(
must=[
models.FieldCondition(
@@ -246,7 +245,6 @@ client.search(
]
),
search_params=models.SearchParams(hnsw_ef=128, exact=False),
query_vector=[0.2, 0.1, 0.9, 0.7],
limit=3,
)
```
@@ -385,9 +383,10 @@ from qdrant_client import QdrantClient
client = QdrantClient(url="http://localhost:6333")
client.search(
client.query_points(
collection_name="{collection_name}",
query_vector=("image", [0.2, 0.1, 0.9, 0.7]),
query=[0.2, 0.1, 0.9, 0.7],
using="image",
limit=3,
)
```
@@ -466,7 +465,7 @@ You can still use payload filtering and other features of the search API with sp
There are however important differences between dense and sparse vector search:
| Index| Sparse Query | Dense Query |
| --- | --- | --- |
| --- | --- | --- |
| Scoring Metric | Default is `Dot product`, no need to specify it | `Distance` has supported metrics e.g. Dot, Cosine |
| Search Type | Always exact in Qdrant | HNSW is an approximate NN |
| Return Behaviour | Returns only vectors with non-zero values in the same indices as the query vector | Returns `limit` vectors |
@@ -490,15 +489,13 @@ from qdrant_client import QdrantClient, models
client = QdrantClient(url="http://localhost:6333")
client.search(
client.query_points(
collection_name="{collection_name}",
query_vector=models.NamedSparseVector(
name="text",
vector=models.SparseVector(
indices=[1, 7],
values=[2.0, 1.0],
),
query=models.SparseVector(
indices=[1, 7],
values=[2.0, 1.0],
),
using="text",
limit=3,
)
```
@@ -598,9 +595,9 @@ POST /collections/{collection_name}/points/query
```
```python
client.search(
client.query_points(
collection_name="{collection_name}",
query_vector=[0.2, 0.1, 0.9, 0.7],
query=[0.2, 0.1, 0.9, 0.7],
with_vectors=True,
with_payload=True,
)
@@ -669,8 +666,8 @@ await client.QueryAsync(
);
```
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`,
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`:
```http
@@ -686,9 +683,9 @@ from qdrant_client import QdrantClient
client = QdrantClient(url="http://localhost:6333")
client.search(
client.query_points(
collection_name="{collection_name}",
query_vector=[0.2, 0.1, 0.9, 0.7],
query=[0.2, 0.1, 0.9, 0.7],
with_payload=["city", "village", "town"],
)
```
@@ -786,9 +783,9 @@ from qdrant_client import QdrantClient, models
client = QdrantClient(url="http://localhost:6333")
client.search(
client.query_points(
collection_name="{collection_name}",
query_vector=[0.2, 0.1, 0.9, 0.7],
query=[0.2, 0.1, 0.9, 0.7],
with_payload=models.PayloadSelectorExclude(
exclude=["city"],
),
@@ -866,8 +863,8 @@ await client.QueryAsync(
```
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
* `payload.nested_field` - for a nested field
* `payload.nested_array[].sub_field` - for projecting nested fields within an array
Accessing array elements by index is currently not supported.
@@ -940,11 +937,11 @@ filter_ = models.Filter(
)
search_queries = [
models.SearchRequest(vector=[0.2, 0.1, 0.9, 0.7], filter=filter_, limit=3),
models.SearchRequest(vector=[0.5, 0.3, 0.2, 0.3], filter=filter_, limit=3),
models.QueryRequest(query=[0.2, 0.1, 0.9, 0.7], filter=filter_, limit=3),
models.QueryRequest(query=[0.5, 0.3, 0.2, 0.3], filter=filter_, limit=3),
]
client.search_batch(collection_name="{collection_name}", requests=search_queries)
client.query_batch_points(collection_name="{collection_name}", requests=search_queries)
```
```typescript
@@ -1113,9 +1110,9 @@ from qdrant_client import QdrantClient
client = QdrantClient(url="http://localhost:6333")
client.search(
client.query_points(
collection_name="{collection_name}",
query_vector=[0.2, 0.1, 0.9, 0.7],
query=[0.2, 0.1, 0.9, 0.7],
with_vectors=True,
with_payload=True,
limit=10,
@@ -1289,10 +1286,10 @@ POST /collections/{collection_name}/points/query/groups
```
```python
client.search_groups(
client.query_points_groups(
collection_name="{collection_name}",
# Same as in the regular search() API
query_vector=[1.1],
# Same as in the regular query_points() API
query=[1.1],
# Grouping parameters
group_by="document_id", # Path of the field to group by
limit=4, # Max amount of groups
@@ -1448,10 +1445,10 @@ POST /collections/chunks/points/query/groups
```
```python
client.search_groups(
client.query_points_groups(
collection_name="chunks",
# Same as in the regular search() API
query_vector=[1.1],
query=[1.1],
# Grouping parameters
group_by="document_id", # Path of the field to group by
limit=2, # Max amount of groups
@@ -1538,20 +1535,20 @@ 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
}
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
}
);
```
@@ -1616,7 +1613,6 @@ Random sampling API is a part of [Universal Query API](#query-api) and can be us
}
```
```python
from qdrant_client import QdrantClient, models
@@ -1679,15 +1675,9 @@ client
using Qdrant.Client;
using Qdrant.Client.Grpc;
var client = new QdrantClient("localhost", 6334);
await client.QueryAsync(
collectionName: "{collection_name}",
query: Sample.Random
);
await client.QueryAsync(collectionName: "{collection_name}", query: Sample.Random);
```
## Query planning
@@ -328,16 +328,11 @@ from qdrant_client import QdrantClient, models
client = QdrantClient(url="http://localhost:6333")
result = client.search(
result = client.query_points(
collection_name="{collection_name}",
query_vector=models.NamedSparseVector(
name="text",
vector=models.SparseVector(
indices=[1, 3, 5, 7],
values=[0.1, 0.2, 0.3, 0.4]
),
)
)
query_vector=models.SparseVector(indices=[1, 3, 5, 7], values=[0.1, 0.2, 0.3, 0.4]),
using="text",
).points
```
```rust
@@ -139,11 +139,11 @@ async with AsyncCliet(token=aa_token) as aa_client:
query_request = SemanticEmbeddingRequest(**query_params)
query_response = await aa_client.semantic_embed(request=query_request, model=model)
results = client.search(
results = client.query_points(
collection_name="COCO",
query_vector=query_response.embedding,
query=query_response.embedding,
limit=3,
)
).points
print(results)
```
@@ -166,11 +166,11 @@ async with AsyncClient(token=aa_token) as aa_client:
query_request = SemanticEmbeddingRequest(**query_params)
query_response = await aa_client.semantic_embed(request=query_request, model=model)
results = client.search(
results = client.query_points(
collection_name="COCO",
query_vector=query_response.embedding,
query=query_response.embedding,
limit=3,
)
).points
print(results)
```
@@ -202,11 +202,11 @@ def search(
model="embed-multilingual-v3.0",
input_type="search_query",
)
results = client.search(
results = client.query_points(
collection_name="personal-notes",
query_vector=response.embeddings[0],
query=response.embeddings[0],
limit=2,
)
).points
return SearchResults(
results=[
Document(**point.payload)
@@ -217,15 +217,13 @@ def to_vector(ratings):
Query Qdrant to find users with similar tastes based on the provided personal ratings. The search returns a list of similar users along with their ratings, facilitating collaborative filtering.
```python
results = client.search(
results = client.query_points(
"movielens",
query_vector=models.NamedSparseVector(
name="ratings",
vector=to_vector(my_ratings)
),
query=to_vector(my_ratings),
using="ratings",
with_vectors=True, # We will use those to find new movies
limit=20
)
).points
```
Movie scores are computed based on how frequently each movie appears in the ratings of similar users, weighted by their ratings. This step identifies popular movies among users with similar tastes. Calculate how frequently each movie is found in similar users' ratings
@@ -1073,8 +1073,9 @@ POST /collections/{collection_name}/points/query?consistency=majority
```
```python
client.search(
client.query_points(
collection_name="{collection_name}",
query=[0.2, 0.1, 0.9, 0.7],
query_filter=models.Filter(
must=[
models.FieldCondition(
@@ -1086,7 +1087,6 @@ client.search(
]
),
search_params=models.SearchParams(hnsw_ef=128, exact=False),
query_vector=[0.2, 0.1, 0.9, 0.7],
limit=3,
consistency="majority",
)
@@ -201,8 +201,9 @@ from qdrant_client import QdrantClient, models
client = QdrantClient(url="http://localhost:6333")
client.search(
client.query_points(
collection_name="{collection_name}",
query=[0.1, 0.1, 0.9],
query_filter=models.Filter(
must=[
models.FieldCondition(
@@ -213,7 +214,6 @@ client.search(
)
]
),
query_vector=[0.1, 0.1, 0.9],
limit=10,
)
```
@@ -176,9 +176,9 @@ from qdrant_client import QdrantClient, models
client = QdrantClient(url="http://localhost:6333")
client.search(
client.query_points(
collection_name="{collection_name}",
query_vector=[0.2, 0.1, 0.9, 0.7],
query=[0.2, 0.1, 0.9, 0.7],
search_params=models.SearchParams(
quantization=models.QuantizationSearchParams(rescore=False)
),
@@ -545,10 +545,10 @@ from qdrant_client import QdrantClient, models
client = QdrantClient(url="http://localhost:6333")
client.search(
client.query_points(
collection_name="{collection_name}",
query=[0.2, 0.1, 0.9, 0.7],
search_params=models.SearchParams(hnsw_ef=128, exact=False),
query_vector=[0.2, 0.1, 0.9, 0.7],
limit=3,
)
```
@@ -589,9 +589,9 @@ from qdrant_client import QdrantClient, models
client = QdrantClient(url="http://localhost:6333")
client.search(
client.query_points(
collection_name="{collection_name}",
query_vector=[0.2, 0.1, 0.9, 0.7],
query=[0.2, 0.1, 0.9, 0.7],
search_params=models.SearchParams(
quantization=models.QuantizationSearchParams(
ignore=False,
@@ -737,9 +737,9 @@ from qdrant_client import QdrantClient, models
client = QdrantClient(url="http://localhost:6333")
client.search(
client.query_points(
collection_name="{collection_name}",
query_vector=[0.2, 0.1, 0.9, 0.7],
query=[0.2, 0.1, 0.9, 0.7],
search_params=models.SearchParams(
quantization=models.QuantizationSearchParams(
ignore=True,
@@ -1001,9 +1001,9 @@ from qdrant_client import QdrantClient, models
client = QdrantClient(url="http://localhost:6333")
client.search(
client.query_points(
collection_name="{collection_name}",
query_vector=[0.2, 0.1, 0.9, 0.7],
query=[0.2, 0.1, 0.9, 0.7],
search_params=models.SearchParams(
quantization=models.QuantizationSearchParams(rescore=False)
),
@@ -300,9 +300,9 @@ status: Completed
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
search_result = client.search(
collection_name="test_collection", query_vector=[0.2, 0.1, 0.9, 0.7], limit=3
)
search_result = client.query_points(
collection_name="test_collection", query=[0.2, 0.1, 0.9, 0.7], limit=3
).points
print(search_result)
```
@@ -399,15 +399,15 @@ We can narrow down the results further by filtering by payload. Let's find the c
```python
from qdrant_client.models import Filter, FieldCondition, MatchValue
search_result = client.search(
search_result = client.query_points(
collection_name="test_collection",
query_vector=[0.2, 0.1, 0.9, 0.7],
query=[0.2, 0.1, 0.9, 0.7],
query_filter=Filter(
must=[FieldCondition(key="city", match=MatchValue(value="London"))]
),
with_payload=True,
limit=3,
)
).points
print(search_result)
```
@@ -66,11 +66,11 @@ async def main():
)
# Search for nearest neighbors
points = await client.search(
points = await client.query_points(
collection_name="my_collection",
query_vector=[0.9, 0.1, 0.1, 0.5],
query=[0.9, 0.1, 0.1, 0.5],
limit=2,
)
).points
# Your async code using AsyncQdrantClient might be put here
# ...
@@ -325,13 +325,12 @@ Fortunately, this model should continue to provide the results you need.</aside>
```python
query = "How do I count points in a collection?"
hits = client.search(
hits = client.query_points(
"qdrant-sources",
query_vector=(
"text", nlp_model.encode(query).tolist()
),
query=nlp_model.encode(query).tolist(),
using="text",
limit=5,
)
).points
```
Now, review the results. The following table lists the module, the file name
@@ -349,13 +348,12 @@ the file.
It seems we were able to find some relevant code structures. Let's try the same with the code embeddings:
```python
hits = client.search(
hits = client.query_points(
"qdrant-sources",
query_vector=(
"code", code_model.encode(query).tolist()
),
query=code_model.encode(query).tolist(),
using="code",
limit=5,
)
).points
```
Output:
@@ -374,27 +372,25 @@ different aspects of the codebase. We can use both models to query the collectio
and then combine the results to get the most relevant code snippets, from a single batch request.
```python
results = client.search_batch(
responses = client.query_batch_points(
"qdrant-sources",
requests=[
models.SearchRequest(
vector=models.NamedVector(
name="text",
vector=nlp_model.encode(query).tolist()
),
models.QueryRequest(
query=nlp_model.encode(query).tolist(),
using="text",
with_payload=True,
limit=5,
),
models.SearchRequest(
vector=models.NamedVector(
name="code",
vector=code_model.encode(query).tolist()
),
models.QueryRequest(
query=code_model.encode(query).tolist(),
using="code",
with_payload=True,
limit=5,
),
]
)
results = [response.points for response in responses]
```
Output:
@@ -195,14 +195,12 @@ From the uploaded list of movies with ratings, we can perform a search in Qdrant
```python
# Perform the search
results = qdrant_client.search(
results = qdrant_client.query_points(
collection_name=collection_name,
query_vector=NamedSparseVector(
name="ratings",
vector=to_vector(my_ratings)
),
query=to_vector(my_ratings),
using="ratings",
limit=20
)
).points
```
Now we can find the movies liked by the other similar users, but we haven't seen yet.
@@ -226,12 +226,12 @@ def search(self, text: str):
vector = self.model.encode(text).tolist()
# Use `vector` for search for closest vectors in the collection
search_result = self.qdrant_client.search(
search_result = self.qdrant_client.query_points(
collection_name=self.collection_name,
query_vector=vector,
query=vector,
query_filter=None, # If you don't want any filters for now
limit=5, # 5 the most closest results is enough
)
).points
# `search_result` contains found vector ids with similarity scores along with the stored payload
# In this function you are interested in payload only
payloads = [hit.payload for hit in search_result]
@@ -260,12 +260,12 @@ from qdrant_client.models import Filter
}]
})
search_result = self.qdrant_client.search(
search_result = self.qdrant_client.query_points(
collection_name=self.collection_name,
query_vector=vector,
query=vector,
query_filter=city_filter,
limit=5
)
).points
...
```
@@ -137,20 +137,20 @@ values of `k`.
def avg_precision_at_k(k: int):
precisions = []
for item in test_dataset:
ann_result = client.search(
ann_result = client.query_points(
collection_name="arxiv-titles-instructorxl-embeddings",
query_vector=item["vector"],
query=item["vector"],
limit=k,
)
).points
knn_result = client.search(
knn_result = client.query_points(
collection_name="arxiv-titles-instructorxl-embeddings",
query_vector=item["vector"],
query=item["vector"],
limit=k,
search_params=models.SearchParams(
exact=True, # Turns on the exact search mode
),
)
).points
# We can calculate the precision@k by comparing the ids of the search results
ann_ids = set(item.id for item in ann_result)
@@ -192,11 +192,12 @@ client.upload_points(
Now that the data is stored in Qdrant, you can ask it questions and receive semantically relevant results.
```python
hits = client.search(
hits = client.query_points(
collection_name="my_books",
query_vector=encoder.encode("alien invasion").tolist(),
query=encoder.encode("alien invasion").tolist(),
limit=3,
)
).points
for hit in hits:
print(hit.payload, "score:", hit.score)
```
@@ -216,14 +217,15 @@ The search engine shows three of the most likely responses that have to do with
How about the most recent book from the early 2000s?
```python
hits = client.search(
hits = client.query_points(
collection_name="my_books",
query_vector=encoder.encode("alien invasion").tolist(),
query=encoder.encode("alien invasion").tolist(),
query_filter=models.Filter(
must=[models.FieldCondition(key="year", range=models.Range(gte=2000))]
),
limit=1,
)
).points
for hit in hits:
print(hit.payload, "score:", hit.score)
```