From 5e3323f9f184169955217f92debd5f765c3917c1 Mon Sep 17 00:00:00 2001 From: qdrant Date: Tue, 4 Apr 2023 11:55:04 +0000 Subject: [PATCH] docs auto-sync --- .../content/documentation/collections.md | 14 + .../content/documentation/filtering.md | 277 +++++++++--------- .../content/documentation/integrations.md | 80 ++++- .../content/documentation/search.md | 4 +- 4 files changed, 230 insertions(+), 145 deletions(-) diff --git a/qdrant-landing/content/documentation/collections.md b/qdrant-landing/content/documentation/collections.md index ac977364f..3d13c6844 100644 --- a/qdrant-landing/content/documentation/collections.md +++ b/qdrant-landing/content/documentation/collections.md @@ -378,3 +378,17 @@ client = QdrantClient("localhost", port=6333) client.list_aliases() ``` + +### List all collections + +```http +GET /collections +``` + +```python +from qdrant_client import QdrantClient + +client = QdrantClient("localhost", port=6333) + +client.get_collections() +``` diff --git a/qdrant-landing/content/documentation/filtering.md b/qdrant-landing/content/documentation/filtering.md index 2aca8eb4f..ea0be08ac 100644 --- a/qdrant-landing/content/documentation/filtering.md +++ b/qdrant-landing/content/documentation/filtering.md @@ -9,9 +9,9 @@ You can impose conditions both on the [payload](../payload) and on, for example, The use of additional conditions is important when, for example, it is impossible to express all the features of the object in the embedding. Examples include a variety of business requirements: stock availability, user location, or desired price range. -## Filtering causes +## Filtering clauses -Qdrant allows you to combine conditions in causes. +Qdrant allows you to combine conditions in clauses. Clauses are different logical operations, such as `OR`, `AND`, and `NOT`. Clauses can be recursively nested into each other so that you can reproduce an arbitrary boolean expression. @@ -21,12 +21,12 @@ Suppose we have a set of points with the following payload: ```json [ - {"id": 1, "city": "London", "color": "green"}, - {"id": 2, "city": "London", "color": "red"}, - {"id": 3, "city": "London", "color": "blue"}, - {"id": 4, "city": "Berlin", "color": "red"}, - {"id": 5, "city": "Moscow", "color": "green"}, - {"id": 6, "city": "Moscow", "color": "blue"} + { "id": 1, "city": "London", "color": "green" }, + { "id": 2, "city": "London", "color": "red" }, + { "id": 3, "city": "London", "color": "blue" }, + { "id": 4, "city": "Berlin", "color": "red" }, + { "id": 5, "city": "Moscow", "color": "green" }, + { "id": 6, "city": "Moscow", "color": "blue" } ] ``` @@ -55,11 +55,11 @@ from qdrant_client.http import models client = QdrantClient(host="localhost", port=6333) client.scroll( - collection_name="{collection_name}", + collection_name="{collection_name}", scroll_filter=models.Filter( must=[ models.FieldCondition( - key="city", + key="city", match=models.MatchValue(value="London"), ), models.FieldCondition( @@ -74,9 +74,7 @@ client.scroll( Filtered points would be: ```json -[ - {"id": 2, "city": "London", "color": "red"} -] +[{ "id": 2, "city": "London", "color": "red" }] ``` When using `must`, the clause becomes `true` only if every condition listed inside `must` is satisfied. @@ -102,15 +100,15 @@ POST /collections/{collection_name}/points/scroll ```python client.scroll( - collection_name="{collection_name}", + collection_name="{collection_name}", scroll_filter=models.Filter( should=[ models.FieldCondition( - key="city", + key="city", match=models.MatchValue(value="London"), ), models.FieldCondition( - key="color", + key="color", match=models.MatchValue(value="red"), ), ] @@ -122,10 +120,10 @@ Filtered points would be: ```json [ - {"id": 1, "city": "London", "color": "green"}, - {"id": 2, "city": "London", "color": "red"}, - {"id": 3, "city": "London", "color": "blue"}, - {"id": 4, "city": "Berlin", "color": "red"} + { "id": 1, "city": "London", "color": "green" }, + { "id": 2, "city": "London", "color": "red" }, + { "id": 3, "city": "London", "color": "blue" }, + { "id": 4, "city": "Berlin", "color": "red" } ] ``` @@ -152,15 +150,15 @@ POST /collections/{collection_name}/points/scroll ```python client.scroll( - collection_name="{collection_name}", + collection_name="{collection_name}", scroll_filter=models.Filter( must_not=[ models.FieldCondition( - key="city", + key="city", match=models.MatchValue(value="London") ), models.FieldCondition( - key="color", + key="color", match=models.MatchValue(value="red") ), ] @@ -172,8 +170,8 @@ Filtered points would be: ```json [ - {"id": 5, "city": "Moscow", "color": "green"}, - {"id": 6, "city": "Moscow", "color": "blue"} + { "id": 5, "city": "Moscow", "color": "green" }, + { "id": 6, "city": "Moscow", "color": "blue" } ] ``` @@ -202,17 +200,17 @@ POST /collections/{collection_name}/points/scroll ```python client.scroll( - collection_name="{collection_name}", + collection_name="{collection_name}", scroll_filter=models.Filter( must=[ models.FieldCondition( - key="city", + key="city", match=models.MatchValue(value="London") ), ], must_not=[ models.FieldCondition( - key="color", + key="color", match=models.MatchValue(value="red") ), ], @@ -224,8 +222,8 @@ Filtered points would be: ```json [ - {"id": 1, "city": "London", "color": "green"}, - {"id": 3, "city": "London", "color": "blue"}, + { "id": 1, "city": "London", "color": "green" }, + { "id": 3, "city": "London", "color": "blue" } ] ``` @@ -253,17 +251,17 @@ POST /collections/{collection_name}/points/scroll ```python client.scroll( - collection_name="{collection_name}", + collection_name="{collection_name}", scroll_filter=models.Filter( must_not=[ models.Filter( must=[ models.FieldCondition( - key="city", + key="city", match=models.MatchValue(value="London") ), models.FieldCondition( - key="color", + key="color", match=models.MatchValue(value="red") ), ], @@ -277,11 +275,11 @@ Filtered points would be: ```json [ - {"id": 1, "city": "London", "color": "green"}, - {"id": 3, "city": "London", "color": "blue"}, - {"id": 4, "city": "Berlin", "color": "red"}, - {"id": 5, "city": "Moscow", "color": "green"}, - {"id": 6, "city": "Moscow", "color": "blue"} + { "id": 1, "city": "London", "color": "green" }, + { "id": 3, "city": "London", "color": "blue" }, + { "id": 4, "city": "Berlin", "color": "red" }, + { "id": 5, "city": "Moscow", "color": "green" }, + { "id": 6, "city": "Moscow", "color": "blue" } ] ``` @@ -293,11 +291,11 @@ Let's look at the existing condition variants and what types of data they apply ### Match ```json -{ - "key": "color", - "match": { - "value": "red" - } +{ + "key": "color", + "match": { + "value": "red" + } } ``` @@ -311,11 +309,11 @@ models.FieldCondition( For the other types, the match condition will look exactly the same, except for the type used: ```json -{ - "key": "count", - "match": { - "value": 0 - } +{ + "key": "count", + "match": { + "value": 0 + } } ``` @@ -332,7 +330,7 @@ You can apply it to [keyword](../payload/#keyword), [integer](../payload/#intege ### Match Any -*Available since version 1.1.0* +_Available since version 1.1.0_ In case you want to check if the stored value is one of multiple values, you can use the Match Any condition. Match Any works as a logical OR for the given values. It can also be described as a `IN` operator. @@ -342,11 +340,11 @@ You can apply it to [keyword](../payload/#keyword) and [integer](../payload/#int Example: ```json -{ - "key": "color", - "match": { - "any": ["black", "yellow"] - } +{ + "key": "color", + "match": { + "any": ["black", "yellow"] + } } ``` @@ -359,10 +357,9 @@ FieldCondition( In this example, the condition will be satisfied if the stored value is either `black` or `yellow`. - ### Nested key -*Available since version 1.1.0* +_Available since version 1.1.0_ Payloads being arbitrary JSON object, it is likely that you will need to filter on a nested field. @@ -372,42 +369,42 @@ Suppose we have a set of points with the following payload: ```json [ - { - "id": 1, - "country": { - "name": "Germany", - "cities": [ - { - "name": "Berlin", - "population": 3.7, - "sightseeing": ["Brandenburg Gate", "Reichstag"] - }, - { - "name": "Munich", - "population": 1.5, - "sightseeing": ["Marienplatz", "Olympiapark"] - } - ] - } - }, - { - "id": 2, - "country": { - "name": "Japan", - "cities": [ - { - "name": "Tokyo", - "population": 9.3, - "sightseeing": ["Tokyo Tower", "Tokyo Skytree"] - }, - { - "name": "Osaka", - "population": 2.7, - "sightseeing": ["Osaka Castle", "Universal Studios Japan"] - } - ] + { + "id": 1, + "country": { + "name": "Germany", + "cities": [ + { + "name": "Berlin", + "population": 3.7, + "sightseeing": ["Brandenburg Gate", "Reichstag"] + }, + { + "name": "Munich", + "population": 1.5, + "sightseeing": ["Marienplatz", "Olympiapark"] } + ] } + }, + { + "id": 2, + "country": { + "name": "Japan", + "cities": [ + { + "name": "Tokyo", + "population": 9.3, + "sightseeing": ["Tokyo Tower", "Tokyo Skytree"] + }, + { + "name": "Osaka", + "population": 2.7, + "sightseeing": ["Osaka Castle", "Universal Studios Japan"] + } + ] + } + } ] ``` @@ -519,11 +516,9 @@ client.scroll( 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. - - ### Full Text Match -*Available since version 0.10.0* +_Available since version 0.10.0_ A special case of the `match` condition is the `text` match condition. It allows you to search for a specific substring, token or phrase within the text field. @@ -534,11 +529,11 @@ Configuration is defined during the index creation and describe at [full-text in If there is no full-text index for the field, the condition will work as exact substring match. ```json -{ - "key": "description", - "match": { - "text": "good cheap" - } +{ + "key": "description", + "match": { + "text": "good cheap" + } } ``` @@ -555,13 +550,13 @@ If the query has several words, then the condition will be satisfied only if all ```json { - "key": "price", - "range": { - "gt": null, - "gte": 100.0, - "lt": null, - "lte": 450.0 - } + "key": "price", + "range": { + "gt": null, + "gte": 100.0, + "lt": null, + "lte": 450.0 + } } ``` @@ -569,9 +564,9 @@ If the query has several words, then the condition will be satisfied only if all models.FieldCondition( key="price", range=models.Range( - gt=None, - gte=100.0, - lt=None, + gt=None, + gte=100.0, + lt=None, lte=450.0, ), ) @@ -595,17 +590,17 @@ Can be applied to [float](../payload/#float) and [integer](../payload/#integer) ```json { - "key": "location", - "geo_bounding_box": { - "bottom_right": { - "lat": 52.495862, - "lon": 13.455868 - }, - "top_left": { - "lat": 52.520711, - "lon": 13.403683 - } + "key": "location", + "geo_bounding_box": { + "bottom_right": { + "lat": 52.495862, + "lon": 13.455868 + }, + "top_left": { + "lat": 52.520711, + "lon": 13.403683 } + } } ``` @@ -631,14 +626,14 @@ It matches with `location`s inside a rectangle with the coordinates of the upper ```json { - "key": "location", - "geo_radius": { - "center": { - "lat": 52.520711, - "lon": 13.403683 - }, - "radius": 1000.0 - } + "key": "location", + "geo_radius": { + "center": { + "lat": 52.520711, + "lon": 13.403683 + }, + "radius": 1000.0 + } } ``` @@ -668,8 +663,8 @@ For example, given the data: ```json [ - {"id": 1, "name": "product A", "comments": ["Very good!", "Excellent"]}, - {"id": 2, "name": "product B", "comments": ["meh", "expected more", "ok"]}, + { "id": 1, "name": "product A", "comments": ["Very good!", "Excellent"] }, + { "id": 2, "name": "product B", "comments": ["meh", "expected more", "ok"] } ] ``` @@ -677,10 +672,10 @@ We can perform the search only among the items with more than two comments: ```json { - "key": "comments", - "values_count": { - "gt": 2 - } + "key": "comments", + "values_count": { + "gt": 2 + } } ``` @@ -694,9 +689,7 @@ models.FieldCondition( The result would be: ```json -[ - {"id": 2, "name": "product B", "comments": ["meh", "expected more", "ok"]}, -] +[{ "id": 2, "name": "product B", "comments": ["meh", "expected more", "ok"] }] ``` If stored value is not an array - it is assumed that the amount of values is equals to 1. @@ -708,9 +701,9 @@ The `IsEmpty` condition may help you with that: ```json { - "is_empty": { - "key": "reports" - } + "is_empty": { + "key": "reports" + } } ``` @@ -744,7 +737,7 @@ POST /collections/{collection_name}/points/scroll ```python client.scroll( - collection_name="{collection_name}", + collection_name="{collection_name}", scroll_filter=models.Filter( must=[ models.HasIdCondition(has_id=[1, 3, 5, 7, 9, 11]), @@ -757,8 +750,8 @@ Filtered points would be: ```json [ - {"id": 1, "city": "London", "color": "green"}, - {"id": 3, "city": "London", "color": "blue"}, - {"id": 5, "city": "Moscow", "color": "green"}, + { "id": 1, "city": "London", "color": "green" }, + { "id": 3, "city": "London", "color": "blue" }, + { "id": 5, "city": "Moscow", "color": "green" } ] ``` diff --git a/qdrant-landing/content/documentation/integrations.md b/qdrant-landing/content/documentation/integrations.md index d6293b5e0..5f225ff9a 100644 --- a/qdrant-landing/content/documentation/integrations.md +++ b/qdrant-landing/content/documentation/integrations.md @@ -6,6 +6,84 @@ Qdrant is a vector database performing an approximate nearest neighbours search as a standalone system, yet, in some cases, you may find it easier to implement your semantic search application using some higher-level libraries. Some of such projects provide ready-to-go integrations and here is a curated list of them. +## LangChain + +LangChain is a library that makes developing Large Language Models based applications much easier. It unifies the interfaces +to different libraries, including major embedding providers and Qdrant. Using LangChain, you can focus on the business value +instead of writing the boilerplate. + +Langchain comes with the Qdrant integration by default. It might be installed with pip: + +```bash +pip install langchain +``` + +Qdrant acts as a vector index that may store the embeddings with the documents used to generate them. There are various ways +how to us it, but calling `Qdrant.from_texts` is probably the most straightforward way how to get started: + +```python +from langchain.vectorstores import Qdrant +from langchain.embeddings import HuggingFaceEmbeddings + +embeddings = HuggingFaceEmbeddings( + model_name="sentence-transformers/all-mpnet-base-v2" +) +doc_store = Qdrant.from_texts( + texts, embeddings, url="", api_key="", collection_name="texts" +) +``` + +Calling `Qdrant.from_documents` or `Qdrant.from_texts` will always recreate the collection and remove all the existing points. +That's fine for some experiments, but you'll prefer not to start from scratch every single time in a real-world scenario. +If you prefer reusing an existing collection, you can create an instance of Qdrant on your own: + +``` +import qdrant_client + +client = qdrant_client.QdrantClient( + "", + api_key="", # For Qdrant Cloud, None for local instance +) + +doc_store = Qdrant( + client=client, collection_name="texts", + embedding_function=embeddings.embed_query, +) +``` + +If you'd like to know more about running Qdrant in a LangChain-based application, please read our article +[Question Answering with LangChain and Qdrant without boilerplate](/articles/langchain-integration/). Some more information +might also be found in the [LangChain documentation](https://python.langchain.com/en/latest/modules/indexes/vectorstores/examples/qdrant.html). + +## LlamaIndex (GPT Index) + +LlamaIndex (formerly GPT Index) acts as an interface between your external data and Large Language Models. So you can bring your +private data and augment LLMs with it. LlamaIndex simplifies data ingestion and indexing, integrating Qdrant as a vector index. + +Installing LlamaIndex is straightforward if we use pip as a package manager: + +```bash +pip install llama-index +``` + +LlamaIndex requires providing an instance of `QdrantClient`, so it can interact with Qdrant server. + +```python +from llama_index import GPTQdrantIndex + +import qdrant_client + +client = qdrant_client.QdrantClient( + "", + api_key="", # For Qdrant Cloud, None for local instance +) + +index = GPTQdrantIndex.from_documents(documents, client=client, collection_name="documents") +``` + +The library [comes with a notebook](https://github.com/jerryjliu/llama_index/blob/main/examples/vector_indices/QdrantIndexDemo.ipynb) +that shows an end-to-end example of how to use Qdrant within LlamaIndex. + ## DocArray You can use Qdrant natively in DocArray, where Qdrant serves as a high-performance document store to enable scalable vector search. @@ -102,7 +180,7 @@ qdrant_client.upsert( collection_name="MyCollection", points=Batch( ids=[1], - vectors=[response["data"]["embedding"]], + vectors=[response["data"][0]["embedding"]], ) ) ``` diff --git a/qdrant-landing/content/documentation/search.md b/qdrant-landing/content/documentation/search.md index 6f97cf493..8c8d9839f 100644 --- a/qdrant-landing/content/documentation/search.md +++ b/qdrant-landing/content/documentation/search.md @@ -301,12 +301,12 @@ filter = models.Filter( ) search_queries = [ - SearchRequest( + models.SearchRequest( vector=[0.2, 0.1, 0.9, 0.7], filter=filter, limit=3 ), - SearchRequest( + models.SearchRequest( vector=[0.5, 0.3, 0.2, 0.3], filter=filter, limit=3