From c8b2663a0cba9b4997d7307f103a40994bebee38 Mon Sep 17 00:00:00 2001 From: trean Date: Fri, 13 Oct 2023 22:09:00 +0200 Subject: [PATCH 1/6] wip: new tutorial pages --- .../InteractiveTutorial/MdxPages/Another.mdx | 15 - .../MdxPages/FilteringClauses.mdx | 196 ++++++ .../MdxPages/FilteringConditions.mdx | 572 ++++++++++++++++++ .../InteractiveTutorial/MdxPages/Index.mdx | 121 +--- .../InteractiveTutorial/MdxPages/Other.mdx | 7 - .../MdxPages/Quickstart.mdx | 110 ++++ .../InteractiveTutorial/TutorialSubpages.jsx | 10 +- src/components/Sidebar/Sidebar.jsx | 9 +- .../Sidebar/SidebarTutorialSection.jsx | 2 +- 9 files changed, 904 insertions(+), 138 deletions(-) delete mode 100644 src/components/InteractiveTutorial/MdxPages/Another.mdx create mode 100644 src/components/InteractiveTutorial/MdxPages/FilteringClauses.mdx create mode 100644 src/components/InteractiveTutorial/MdxPages/FilteringConditions.mdx delete mode 100644 src/components/InteractiveTutorial/MdxPages/Other.mdx create mode 100644 src/components/InteractiveTutorial/MdxPages/Quickstart.mdx diff --git a/src/components/InteractiveTutorial/MdxPages/Another.mdx b/src/components/InteractiveTutorial/MdxPages/Another.mdx deleted file mode 100644 index 6b9f6061..00000000 --- a/src/components/InteractiveTutorial/MdxPages/Another.mdx +++ /dev/null @@ -1,15 +0,0 @@ -export const title = "Another Page" - -# {title} - -Rename this file and edit it to create another page. - -```json withRunButton=true -PUT collections/test_collection2 -{ - "vectors": { - "size": 4, - "distance": "Dot" - } -} -``` diff --git a/src/components/InteractiveTutorial/MdxPages/FilteringClauses.mdx b/src/components/InteractiveTutorial/MdxPages/FilteringClauses.mdx new file mode 100644 index 00000000..e2acb560 --- /dev/null +++ b/src/components/InteractiveTutorial/MdxPages/FilteringClauses.mdx @@ -0,0 +1,196 @@ +export const title = "Filtering Clauses" + +# {title} + +Click RUN button at code blocks to see a result of the query in the right part of the screen.
Click inside a code block to edit it.
+
+ +Qdrant support filtering of collections combining condition and clauses. +In this tutorial you will learn how to filter collections using **filtering 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. + +Let's start with creating a new collection and populating it with points. + +## Set up for this tutorial + +
+ Run these two steps: + + 1. Create a collection: + + ```json withRunButton="true" + PUT collections/demo1 + { + "vectors": { + "size": 4, + "distance": "Dot" + } + } + ``` + +2. And add points to it: + +```json withRunButton="true" +PUT /collections/demo1/points +{ + "points": [ + { "id": 1, "vector": [0.1, 0.2, 0.3, 0.4], "payload": { "city": "London", "color": "green" } }, + { "id": 2, "vector": [0.2, 0.3, 0.4, 0.5], "payload": { "city": "London", "color": "red" } }, + { "id": 3, "vector": [0.3, 0.4, 0.5, 0.6], "payload": { "city": "London", "color": "blue" } }, + { "id": 4, "vector": [0.4, 0.5, 0.6, 0.7], "payload": { "city": "Berlin", "color": "red" } }, + { "id": 5, "vector": [0.5, 0.6, 0.7, 0.8], "payload": { "city": "Moscow", "color": "green" } }, + { "id": 6, "vector": [0.6, 0.7, 0.8, 0.9], "payload": { "city": "Moscow", "color": "blue" } } + ] +} +``` +
+ +Take a note of what data we put into points' `payload` field. + +## Must + +When using `must`, the clause becomes `true` only if every condition listed inside `must` is satisfied. +In this sense, `must` is equivalent to the operator `AND`. + +Example: + +``` json withRunButton="true" +POST /collections/demo1/points/scroll + +{ + "filter": { + "must": [ + { "key": "city", "match": { "value": "London" } }, + { "key": "color", "match": { "value": "red" } } + ] + } +} +``` + +Filtered points would be: + +```json +[{ "id": 2, "payload": { "city": "London", "color": "red" } }] +``` + +## Should + +When using `should`, the clause becomes `true` if at least one condition listed inside `should` is satisfied. +In this sense, `should` is equivalent to the operator `OR`. + +Example: + +```json withRunButton="true" +POST /collections/demo1/points/scroll + +{ + "filter": { + "should": [ + { "key": "city", "match": { "value": "London" } }, + { "key": "color", "match": { "value": "red" } } + ] + } +} +``` + +Filtered points would be: + +```json +[ + { "id": 1, "payload": { "city": "London", "color": "green" } }, + { "id": 2, "payload": { "city": "London", "color": "red" } }, + { "id": 3, "payload": { "city": "London", "color": "blue" } }, + { "id": 4, "payload": { "city": "Berlin", "color": "red" } } +] +``` + +## Must Not + +When using `must_not`, the clause becomes `true` if none if the conditions listed inside `should` is satisfied. +In this sense, `must_not` is equivalent to the expression `(NOT A) AND (NOT B) AND (NOT C)`. + +Example: + +```json withRunButton="true" +POST /collections/demo1/points/scroll +{ + "filter": { + "must_not": [ + { "key": "city", "match": { "value": "London" } }, + { "key": "color", "match": { "value": "red" } } + ] + } +} +``` + +Filtered points would be: + +```json +[ + { "id": 5, "payload": { "city": "Moscow", "color": "green" } }, + { "id": 6, "payload": { "city": "Moscow", "color": "blue" } } +] +``` + +## Clauses combination + +It is also possible to use several clauses simultaneously: + +```json withRunButton="true" +POST /collections/demo1/points/scroll +{ + "filter": { + "must": [ + { "key": "city", "match": { "value": "London" } } + ], + "must_not": [ + { "key": "color", "match": { "value": "red" } } + ] + } +} +``` + +Filtered points would be: + +```json +[ + { "id": 1, "payload": { "city": "London", "color": "green" } }, + { "id": 3, "payload": { "city": "London", "color": "blue" } } +] +``` + +In this case, the conditions are combined by `AND`. + +Also, the conditions could be recursively nested. Example: + +```json withRunButton="true" +POST /collections/demo1/points/scroll +{ + "filter": { + "must_not": [ + { + "must": [ + { "key": "city", "match": { "value": "London" } }, + { "key": "color", "match": { "value": "red" } } + ] + } + ] + } +} +``` + +Filtered points would be: + +```json +[ + { "id": 1, "payload": { "city": "London", "color": "green" } }, + { "id": 3, "payload": { "city": "London", "color": "blue" } }, + { "id": 4, "payload": { "city": "Berlin", "color": "red" } }, + { "id": 5, "payload": { "city": "Moscow", "color": "green" } }, + { "id": 6, "payload": { "city": "Moscow", "color": "blue" } } +] +``` + +In the next tutorial, you will learn how to use **filtering conditions**. diff --git a/src/components/InteractiveTutorial/MdxPages/FilteringConditions.mdx b/src/components/InteractiveTutorial/MdxPages/FilteringConditions.mdx new file mode 100644 index 00000000..dc1169e8 --- /dev/null +++ b/src/components/InteractiveTutorial/MdxPages/FilteringConditions.mdx @@ -0,0 +1,572 @@ +export const title = "Filtering Conditions" + +# {title} + +Setting additional conditions is important when 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. + +Different types of values in payload correspond to different kinds of queries that we can apply to them. +Let's look at the existing condition variants and what types of data they apply to. + +## Match + +```json +POST collections/test_collection/points/search +{ + "vector": [0.2, 0.1, 0.9, 0.7], + "filter": { + "must": [ + { + "key": "color", + "match": { + "value": "red" + } + } + ] + }, + "limit": 3 +} +``` + +For the other types, the match condition will look exactly the same, except for the type used: + +```json +{ + "key": "count", + "match": { + "value": 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. + +### Match Any + +*Available as of v1.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. + +You can apply it to [keyword](../payload/#keyword) and [integer](../payload/#integer) payloads. + +Example: + +```json +{ + "key": "color", + "match": { + "any": ["black", "yellow"] + } +} +``` + +In this example, the condition will be satisfied if the stored value is either `black` or `yellow`. + +If the stored value is an array, it should have at least one value matching any of the given values. E.g. if the stored value is `["black", "green"]`, the condition will be satisfied, because `"black"` is in `["black", "yellow"]`. + + +### Match Except + +*Available as of v1.2.0* + +In case you want to check if the stored value is not one of multiple values, you can use the Match Except condition. +Match Except works as a logical NOR for the given values. +It can also be described as a `NOT IN` operator. + +You can apply it to [keyword](../payload/#keyword) and [integer](../payload/#integer) payloads. + +Example: + +```json +{ + "key": "color", + "match": { + "except": ["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"`. + +### Nested key + +*Available as of v1.1.0* + +Payloads being arbitrary JSON object, it is likely that you will need to filter on a nested field. + +For convenience, we use a syntax similar to what can be found in the [Jq](https://stedolan.github.io/jq/manual/#Basicfilters) project. + +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"] + } + ] + } + } +] +``` + +You can search on a nested field using a dot notation. + +```json withRunButton=true +POST /collections/{collection_name}/points/scroll + +{ + "filter": { + "should": [ + { + "key": "country.name", + "match": { + "value": "Germany" + } + } + ] + } +} +``` + +You can also search through arrays by projecting inner values using the `[]` syntax. + +```json withRunButton=true +POST /collections/{collection_name}/points/scroll + +{ + "filter": { + "should": [ + { + "key": "country.cities[].population", + "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. + +```json withRunButton=true +POST /collections/{collection_name}/points/scroll + +{ + "filter": { + "should": [ + { + "key": "country.cities[].sightseeing", + "match": { + "value": "Osaka Castle" + } + } + ] + } +} +``` + +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 + +*Available as of v1.2.0* + +By default, the conditions are taking into account the entire payload of a point. + +For instance, given two points with the following payload: + +```json +[ + { + "id": 1, + "dinosaur": "t-rex", + "diet": [ + { "food": "leaves", "likes": false}, + { "food": "meat", "likes": true} + ] + }, + { + "id": 2, + "dinosaur": "diplodocus", + "diet": [ + { "food": "leaves", "likes": true}, + { "food": "meat", "likes": false} + ] + } +] +``` + +The following query would match both points: + +```json withRunButton=true +POST /collections/{collection_name}/points/scroll + +{ + "filter": { + "must": [ + { + "key": "diet[].food", + "match": { + "value": "meat" + } + }, + { + "key": "diet[].likes", + "match": { + "value": 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` +- the "diplodocus" matches food=meat on `diet[1].food` and likes=true on `diet[0].likes` + +To retrieve only the points which are matching the conditions on an array element basis, that is the point with id 1 in this example, you would need to use a nested object filter. + +Nested object filters allow arrays of objects to be queried independently of each other. + +It is achieved by using the `nested` condition type formed by a payload key to focus on and a filter to apply. + +The key should point to an array of objects and can be used with or without the bracket notation ("data" or "data[]"). + +```json withRunButton=true +POST /collections/{collection_name}/points/scroll + +{ + "filter": { + "must": [ + "nested": { + { + "key": "diet", + "filter":{ + "must": [ + { + "key": "food", + "match": { + "value": "meat" + } + }, + { + "key": "likes", + "match": { + "value": 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. +Parent document is considered to match the condition if at least one element of the array matches the nested filter. + +**Limitations** + +The `has_id` condition is not supported within the nested object filter. If you need it, place it in an adjacent `must` clause. + +```json withRunButton=true +POST /collections/{collection_name}/points/scroll + +{ + "filter": { + "must": [ + "nested": { + { + "key": "diet", + "filter":{ + "must": [ + { + "key": "food", + "match": { + "value": "meat" + } + }, + { + "key": "likes", + "match": { + "value": true + } + } + ] + } + } + }, + { "has_id": [1] } + ] + } +} +``` + +## Full Text Match + +*Available as of v0.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. + +Exact texts that will match the condition depend on full-text index configuration. +Configuration is defined during the index creation and describe at [full-text index](../indexing/#full-text-index). + +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" + } +} +``` + +If the query has several words, then the condition will be satisfied only if all of them are present in the text. + +## Range + +```json +{ + "key": "price", + "range": { + "gt": null, + "gte": 100.0, + "lt": null, + "lte": 450.0 + } +} +``` + +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. + +Comparisons that can be used: + +- `gt` - greater than +- `gte` - greater than or equal +- `lt` - less than +- `lte` - less than or equal + +Can be applied to [float](../payload/#float) and [integer](../payload/#integer) payloads. + +### Geo + +#### Geo Bounding Box + +```json +{ + "key": "location", + "geo_bounding_box": { + "bottom_right": { + "lon": 13.455868, + "lat": 52.495862 + }, + "top_left": { + "lon": 13.403683, + "lat": 52.520711 + } + } +} +``` + +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 + +```json +{ + "key": "location", + "geo_radius": { + "center": { + "lon": 13.403683, + "lat": 52.520711 + }, + "radius": 1000.0 + } +} +``` + +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. +These conditions can only be applied to payloads that match the [geo-data format](../payload/#geo). + +#### Geo Polygon +Geo Polygons search is useful for when you want to find points inside an irregularly shaped area, for example a country boundary or a forest boundary. A polygon always has an exterior ring and may optionally include interior rings. A lake with an island would be an example of an interior ring. If you wanted to find points in the water but not on the island, you would make an interior ring for the island. + +When defining a ring, you must pick either a clockwise or counterclockwise ordering for your points. The first and last point of the polygon must be the same. + +Currently, we only support unprojected global coordinates (decimal degrees longitude and latitude) and we are datum agnostic. + +```json + +{ + "key": "location", + "geo_polygon": { + "exterior": { + "points": [ + { "lon": -70.0, "lat": -70.0 }, + { "lon": 60.0, "lat": -70.0 }, + { "lon": 60.0, "lat": 60.0 }, + { "lon": -70.0, "lat": 60.0 }, + { "lon": -70.0, "lat": -70.0 } + ] + }, + "interiors": [ + { + "points": [ + { "lon": -65.0, "lat": -65.0 }, + { "lon": 0.0, "lat": -65.0 }, + { "lon": 0.0, "lat": 0.0 }, + { "lon": -65.0, "lat": 0.0 }, + { "lon": -65.0, "lat": -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. +These conditions can only be applied to payloads that match the [geo-data format](../payload/#geo). + +### Values count + +In addition to the direct value comparison, it is also possible to filter by the amount of values. + +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"] } +] +``` + +We can perform the search only among the items with more than two comments: + +```json +{ + "key": "comments", + "values_count": { + "gt": 2 + } +} +``` + +The result would be: + +```json +[{ "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. + +### Is Empty + +Sometimes it is also useful to filter out records that are missing some value. +The `IsEmpty` condition may help you with that: + +```json +{ + "is_empty": { + "key": "reports" + } +} +``` + +This condition will match all records where the field `reports` either does not exist, or has `null` or `[]` value. + + + +### Is Null + +It is not possible to test for `NULL` values with the match condition. +We have to use `IsNull` condition instead: + +```json +{ + "is_null": { + "key": "reports" + } +} +``` + +This condition will match all records where the field `reports` exists and has `NULL` value. + + +### Has id + +This type of query is not related to payload, but can be very useful in some situations. +For example, the user could mark some specific search results as irrelevant, or we want to search only among the specified points. + +```json withRunButton=true +POST /collections/demo1/points/scroll + +{ + "filter": { + "must": [ + { "has_id": [1,3,5,7,9,11] } + ] + } + ... +} +``` + +Filtered points would be: + +```json +[ + { "id": 1, "city": "London", "color": "green" }, + { "id": 3, "city": "London", "color": "blue" }, + { "id": 5, "city": "Moscow", "color": "green" } +] +``` diff --git a/src/components/InteractiveTutorial/MdxPages/Index.mdx b/src/components/InteractiveTutorial/MdxPages/Index.mdx index 714a4593..21909cc0 100644 --- a/src/components/InteractiveTutorial/MdxPages/Index.mdx +++ b/src/components/InteractiveTutorial/MdxPages/Index.mdx @@ -1,115 +1,24 @@ -
- **Table of Contents** -- [Introduction](#/tutorial/another-page) -- [Installation](#/tutorial/other) -
-
- # Interactive Tutorial -In this short example, you will create a Collection, load data into it and run a basic search query. - -Click RUN button at code blocks to see a result of the query in the right part of the screen. - -## 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. - -```json withRunButton=true -PUT collections/test_collection -{ - "vectors": { - "size": 4, - "distance": "Dot" - } -} -``` - -## Add vectors - -Let's now add a few vectors with a payload. Payloads are other data you want to associate with the vector: +## What is Qdrant? -```json withRunButton=true -PUT collections/test_collection/points -{ - "points": [ - { - "id": 1, - "vector": [0.05, 0.61, 0.76, 0.74], - "payload": {"city": "Berlin"} - }, - { - "id": 2, - "vector": [0.19, 0.81, 0.75, 0.11], - "payload": {"city": "London"} - }, - { - "id": 3, - "vector": [0.36, 0.55, 0.47, 0.94], - "payload": {"city": "Moscow"} - }, - { - "id": 4, - "vector": [0.18, 0.01, 0.85, 0.80], - "payload": {"city": "New York"} - }, - { - "id": 5, - "vector": [0.24, 0.18, 0.22, 0.44], - "payload": {"city": "Beijing"} - }, - { - "id": 6, - "vector": [0.35, 0.08, 0.11, 0.44], - "payload": {"city": "Mumbai"} - } - ] -} -``` +Qdrant “is a vector similarity search engine that provides a production-ready service with a convenient API to store, search, and manage points (i.e. vectors) with an additional payload.” +You can think of the payloads as additional pieces of information that can help you hone in on your search and also receive useful information that you can give to your users. -## Run a query +You can get started using Qdrant with the Python qdrant-client, by pulling the latest docker image of qdrant and connecting to it locally, or by trying out Qdrant’s Cloud free tier option until you are ready to make the full switch. -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]`? +## What is a interactive tutorial? -```json withRunButton=true -POST collections/test_collection/points/search -{ - "vector": [0.2, 0.1, 0.9, 0.7], - "limit": 3 -} -``` +In this tutorial, we will guide you through using Qdrant to search for vectors similar to a given vector. +You will be able to run the code blocks in this tutorial and see the results in real-time. +You also can edit the code blocks and see how the results change. -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](https://qdrant.tech/documentation/concepts/search#payload-and-vector-in-the-result) on how to enable it. -## Add a filter - -We can narrow down the results further by filtering by payload. Let's find the closest results that include "London". - -```json withRunButton=true -POST collections/test_collection/points/search -{ - "vector": [0.2, 0.1, 0.9, 0.7], - "filter": { - "must": [ - { - "key": "city", - "match": { - "value": "London" - } - } - ] - }, - "limit": 3 -} -``` - -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](https://qdrant.tech/documentation/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](https://qdrant.tech/documentation/tutorials/) and create your own app with the help of our [Examples](https://qdrant.tech/documentation/examples/). +
+ **Table of Contents** + - [Quickstart](#/tutorial/quickstart) + - [Filtering Clauses](#/tutorial/filtering-clauses) + - [Filtering Conditions](#/tutorial/filtering-conditions) +
+
-**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. diff --git a/src/components/InteractiveTutorial/MdxPages/Other.mdx b/src/components/InteractiveTutorial/MdxPages/Other.mdx deleted file mode 100644 index 7218714d..00000000 --- a/src/components/InteractiveTutorial/MdxPages/Other.mdx +++ /dev/null @@ -1,7 +0,0 @@ -export const title = "Something Other" - -# {title} - -Rename this file and edit it to create another page. - -This is success, you read everything! diff --git a/src/components/InteractiveTutorial/MdxPages/Quickstart.mdx b/src/components/InteractiveTutorial/MdxPages/Quickstart.mdx new file mode 100644 index 00000000..880b41b3 --- /dev/null +++ b/src/components/InteractiveTutorial/MdxPages/Quickstart.mdx @@ -0,0 +1,110 @@ +export const title = 'Quickstart'; + +# {title} + +In this short example, you will create a Collection, load data into it and run a basic search query. + +Click RUN button at code blocks to see a result of the query in the right part of the screen. + +## 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. + +```json withRunButton=true +PUT collections/test_collection +{ + "vectors": { + "size": 4, + "distance": "Dot" + } +} +``` + +## Add vectors + +Let's now add a few vectors with a payload. Payloads are other data you want to associate with the vector: + +```json withRunButton=true +PUT collections/test_collection/points +{ + "points": [ + { + "id": 1, + "vector": [0.05, 0.61, 0.76, 0.74], + "payload": {"city": "Berlin"} + }, + { + "id": 2, + "vector": [0.19, 0.81, 0.75, 0.11], + "payload": {"city": "London"} + }, + { + "id": 3, + "vector": [0.36, 0.55, 0.47, 0.94], + "payload": {"city": "Moscow"} + }, + { + "id": 4, + "vector": [0.18, 0.01, 0.85, 0.80], + "payload": {"city": "New York"} + }, + { + "id": 5, + "vector": [0.24, 0.18, 0.22, 0.44], + "payload": {"city": "Beijing"} + }, + { + "id": 6, + "vector": [0.35, 0.08, 0.11, 0.44], + "payload": {"city": "Mumbai"} + } + ] +} +``` + +## 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]`? + +```json withRunButton=true +POST collections/test_collection/points/search +{ + "vector": [0.2, 0.1, 0.9, 0.7], + "limit": 3 +} +``` + +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](https://qdrant.tech/documentation/concepts/search#payload-and-vector-in-the-result) on how to enable it. + +## Add a filter + +We can narrow down the results further by filtering by payload. Let's find the closest results that include "London". + +```json withRunButton=true +POST collections/test_collection/points/search +{ + "vector": [0.2, 0.1, 0.9, 0.7], + "filter": { + "must": [ + { + "key": "city", + "match": { + "value": "London" + } + } + ] + }, + "limit": 3 +} +``` + +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](https://qdrant.tech/documentation/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](https://qdrant.tech/documentation/tutorials/) and create your own app with the help of our [Examples](https://qdrant.tech/documentation/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. diff --git a/src/components/InteractiveTutorial/TutorialSubpages.jsx b/src/components/InteractiveTutorial/TutorialSubpages.jsx index bd3e7003..d3417513 100644 --- a/src/components/InteractiveTutorial/TutorialSubpages.jsx +++ b/src/components/InteractiveTutorial/TutorialSubpages.jsx @@ -1,6 +1,7 @@ -import * as Another from './MdxPages/Another.mdx'; -import * as Other from './MdxPages/Other.mdx'; import * as Index from './MdxPages/Index.mdx'; +import * as Quickstart from './MdxPages/Quickstart.mdx'; +import * as FilteringClauses from './MdxPages/FilteringClauses.mdx'; +import * as FilteringConditions from './MdxPages/FilteringConditions.mdx'; /** * MDX page object (Index etc.) contains: @@ -11,8 +12,9 @@ import * as Index from './MdxPages/Index.mdx'; export const tutorialIndexPage = Index; const tutorialSubPages = [ - ['another-page', Another], - ['other', Other], + ['quickstart', Quickstart], + ['filtering-clauses', FilteringClauses], + ['filtering-conditions', FilteringConditions], ]; export { tutorialSubPages }; diff --git a/src/components/Sidebar/Sidebar.jsx b/src/components/Sidebar/Sidebar.jsx index 6f6f59cd..a07f5aa8 100644 --- a/src/components/Sidebar/Sidebar.jsx +++ b/src/components/Sidebar/Sidebar.jsx @@ -6,7 +6,7 @@ import { List, Typography, Divider, ListItem, ListItemButton, ListItemIcon, List import { Link } from 'react-router-dom'; import { LibraryBooks, Terminal } from '@mui/icons-material'; import Tooltip from '@mui/material/Tooltip'; -// import SidebarTutorialSection from './SidebarTutorialSection'; +import SidebarTutorialSection from './SidebarTutorialSection'; const drawerWidth = 240; @@ -111,10 +111,9 @@ export default function Sidebar({ open, version }) { - {/* todo: uncomment when tutorial is ready*/} - {/* */} - {/* */} - {/* */} + + + diff --git a/src/components/Sidebar/SidebarTutorialSection.jsx b/src/components/Sidebar/SidebarTutorialSection.jsx index 9a0a6336..47da55b1 100644 --- a/src/components/Sidebar/SidebarTutorialSection.jsx +++ b/src/components/Sidebar/SidebarTutorialSection.jsx @@ -10,7 +10,7 @@ const TutorialsList = tutorialSubPages.map((page) => { const [slug, pageObject] = page; return ( - + Date: Mon, 16 Oct 2023 15:49:20 +0200 Subject: [PATCH 2/6] tutorila pages --- .../MdxPages/FilteringClauses.mdx | 53 +- .../MdxPages/FilteringConditions.mdx | 572 ------------------ .../InteractiveTutorial/MdxPages/Index.mdx | 1 - .../MdxPages/Quickstart.mdx | 2 +- .../InteractiveTutorial/TutorialSubpages.jsx | 2 - 5 files changed, 3 insertions(+), 627 deletions(-) delete mode 100644 src/components/InteractiveTutorial/MdxPages/FilteringConditions.mdx diff --git a/src/components/InteractiveTutorial/MdxPages/FilteringClauses.mdx b/src/components/InteractiveTutorial/MdxPages/FilteringClauses.mdx index e2acb560..14db711a 100644 --- a/src/components/InteractiveTutorial/MdxPages/FilteringClauses.mdx +++ b/src/components/InteractiveTutorial/MdxPages/FilteringClauses.mdx @@ -2,7 +2,7 @@ export const title = "Filtering Clauses" # {title} -Click RUN button at code blocks to see a result of the query in the right part of the screen.
Click inside a code block to edit it.
+Click **RUN** button at code blocks to see a result of the query in the right part of the screen.
Click inside a code block to edit it.

Qdrant support filtering of collections combining condition and clauses. @@ -54,7 +54,7 @@ Take a note of what data we put into points' `payload` field. When using `must`, the clause becomes `true` only if every condition listed inside `must` is satisfied. In this sense, `must` is equivalent to the operator `AND`. -Example: +Run the next example: ``` json withRunButton="true" POST /collections/demo1/points/scroll @@ -69,12 +69,6 @@ POST /collections/demo1/points/scroll } ``` -Filtered points would be: - -```json -[{ "id": 2, "payload": { "city": "London", "color": "red" } }] -``` - ## Should When using `should`, the clause becomes `true` if at least one condition listed inside `should` is satisfied. @@ -95,17 +89,6 @@ POST /collections/demo1/points/scroll } ``` -Filtered points would be: - -```json -[ - { "id": 1, "payload": { "city": "London", "color": "green" } }, - { "id": 2, "payload": { "city": "London", "color": "red" } }, - { "id": 3, "payload": { "city": "London", "color": "blue" } }, - { "id": 4, "payload": { "city": "Berlin", "color": "red" } } -] -``` - ## Must Not When using `must_not`, the clause becomes `true` if none if the conditions listed inside `should` is satisfied. @@ -125,15 +108,6 @@ POST /collections/demo1/points/scroll } ``` -Filtered points would be: - -```json -[ - { "id": 5, "payload": { "city": "Moscow", "color": "green" } }, - { "id": 6, "payload": { "city": "Moscow", "color": "blue" } } -] -``` - ## Clauses combination It is also possible to use several clauses simultaneously: @@ -152,15 +126,6 @@ POST /collections/demo1/points/scroll } ``` -Filtered points would be: - -```json -[ - { "id": 1, "payload": { "city": "London", "color": "green" } }, - { "id": 3, "payload": { "city": "London", "color": "blue" } } -] -``` - In this case, the conditions are combined by `AND`. Also, the conditions could be recursively nested. Example: @@ -180,17 +145,3 @@ POST /collections/demo1/points/scroll } } ``` - -Filtered points would be: - -```json -[ - { "id": 1, "payload": { "city": "London", "color": "green" } }, - { "id": 3, "payload": { "city": "London", "color": "blue" } }, - { "id": 4, "payload": { "city": "Berlin", "color": "red" } }, - { "id": 5, "payload": { "city": "Moscow", "color": "green" } }, - { "id": 6, "payload": { "city": "Moscow", "color": "blue" } } -] -``` - -In the next tutorial, you will learn how to use **filtering conditions**. diff --git a/src/components/InteractiveTutorial/MdxPages/FilteringConditions.mdx b/src/components/InteractiveTutorial/MdxPages/FilteringConditions.mdx deleted file mode 100644 index dc1169e8..00000000 --- a/src/components/InteractiveTutorial/MdxPages/FilteringConditions.mdx +++ /dev/null @@ -1,572 +0,0 @@ -export const title = "Filtering Conditions" - -# {title} - -Setting additional conditions is important when 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. - -Different types of values in payload correspond to different kinds of queries that we can apply to them. -Let's look at the existing condition variants and what types of data they apply to. - -## Match - -```json -POST collections/test_collection/points/search -{ - "vector": [0.2, 0.1, 0.9, 0.7], - "filter": { - "must": [ - { - "key": "color", - "match": { - "value": "red" - } - } - ] - }, - "limit": 3 -} -``` - -For the other types, the match condition will look exactly the same, except for the type used: - -```json -{ - "key": "count", - "match": { - "value": 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. - -### Match Any - -*Available as of v1.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. - -You can apply it to [keyword](../payload/#keyword) and [integer](../payload/#integer) payloads. - -Example: - -```json -{ - "key": "color", - "match": { - "any": ["black", "yellow"] - } -} -``` - -In this example, the condition will be satisfied if the stored value is either `black` or `yellow`. - -If the stored value is an array, it should have at least one value matching any of the given values. E.g. if the stored value is `["black", "green"]`, the condition will be satisfied, because `"black"` is in `["black", "yellow"]`. - - -### Match Except - -*Available as of v1.2.0* - -In case you want to check if the stored value is not one of multiple values, you can use the Match Except condition. -Match Except works as a logical NOR for the given values. -It can also be described as a `NOT IN` operator. - -You can apply it to [keyword](../payload/#keyword) and [integer](../payload/#integer) payloads. - -Example: - -```json -{ - "key": "color", - "match": { - "except": ["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"`. - -### Nested key - -*Available as of v1.1.0* - -Payloads being arbitrary JSON object, it is likely that you will need to filter on a nested field. - -For convenience, we use a syntax similar to what can be found in the [Jq](https://stedolan.github.io/jq/manual/#Basicfilters) project. - -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"] - } - ] - } - } -] -``` - -You can search on a nested field using a dot notation. - -```json withRunButton=true -POST /collections/{collection_name}/points/scroll - -{ - "filter": { - "should": [ - { - "key": "country.name", - "match": { - "value": "Germany" - } - } - ] - } -} -``` - -You can also search through arrays by projecting inner values using the `[]` syntax. - -```json withRunButton=true -POST /collections/{collection_name}/points/scroll - -{ - "filter": { - "should": [ - { - "key": "country.cities[].population", - "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. - -```json withRunButton=true -POST /collections/{collection_name}/points/scroll - -{ - "filter": { - "should": [ - { - "key": "country.cities[].sightseeing", - "match": { - "value": "Osaka Castle" - } - } - ] - } -} -``` - -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 - -*Available as of v1.2.0* - -By default, the conditions are taking into account the entire payload of a point. - -For instance, given two points with the following payload: - -```json -[ - { - "id": 1, - "dinosaur": "t-rex", - "diet": [ - { "food": "leaves", "likes": false}, - { "food": "meat", "likes": true} - ] - }, - { - "id": 2, - "dinosaur": "diplodocus", - "diet": [ - { "food": "leaves", "likes": true}, - { "food": "meat", "likes": false} - ] - } -] -``` - -The following query would match both points: - -```json withRunButton=true -POST /collections/{collection_name}/points/scroll - -{ - "filter": { - "must": [ - { - "key": "diet[].food", - "match": { - "value": "meat" - } - }, - { - "key": "diet[].likes", - "match": { - "value": 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` -- the "diplodocus" matches food=meat on `diet[1].food` and likes=true on `diet[0].likes` - -To retrieve only the points which are matching the conditions on an array element basis, that is the point with id 1 in this example, you would need to use a nested object filter. - -Nested object filters allow arrays of objects to be queried independently of each other. - -It is achieved by using the `nested` condition type formed by a payload key to focus on and a filter to apply. - -The key should point to an array of objects and can be used with or without the bracket notation ("data" or "data[]"). - -```json withRunButton=true -POST /collections/{collection_name}/points/scroll - -{ - "filter": { - "must": [ - "nested": { - { - "key": "diet", - "filter":{ - "must": [ - { - "key": "food", - "match": { - "value": "meat" - } - }, - { - "key": "likes", - "match": { - "value": 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. -Parent document is considered to match the condition if at least one element of the array matches the nested filter. - -**Limitations** - -The `has_id` condition is not supported within the nested object filter. If you need it, place it in an adjacent `must` clause. - -```json withRunButton=true -POST /collections/{collection_name}/points/scroll - -{ - "filter": { - "must": [ - "nested": { - { - "key": "diet", - "filter":{ - "must": [ - { - "key": "food", - "match": { - "value": "meat" - } - }, - { - "key": "likes", - "match": { - "value": true - } - } - ] - } - } - }, - { "has_id": [1] } - ] - } -} -``` - -## Full Text Match - -*Available as of v0.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. - -Exact texts that will match the condition depend on full-text index configuration. -Configuration is defined during the index creation and describe at [full-text index](../indexing/#full-text-index). - -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" - } -} -``` - -If the query has several words, then the condition will be satisfied only if all of them are present in the text. - -## Range - -```json -{ - "key": "price", - "range": { - "gt": null, - "gte": 100.0, - "lt": null, - "lte": 450.0 - } -} -``` - -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. - -Comparisons that can be used: - -- `gt` - greater than -- `gte` - greater than or equal -- `lt` - less than -- `lte` - less than or equal - -Can be applied to [float](../payload/#float) and [integer](../payload/#integer) payloads. - -### Geo - -#### Geo Bounding Box - -```json -{ - "key": "location", - "geo_bounding_box": { - "bottom_right": { - "lon": 13.455868, - "lat": 52.495862 - }, - "top_left": { - "lon": 13.403683, - "lat": 52.520711 - } - } -} -``` - -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 - -```json -{ - "key": "location", - "geo_radius": { - "center": { - "lon": 13.403683, - "lat": 52.520711 - }, - "radius": 1000.0 - } -} -``` - -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. -These conditions can only be applied to payloads that match the [geo-data format](../payload/#geo). - -#### Geo Polygon -Geo Polygons search is useful for when you want to find points inside an irregularly shaped area, for example a country boundary or a forest boundary. A polygon always has an exterior ring and may optionally include interior rings. A lake with an island would be an example of an interior ring. If you wanted to find points in the water but not on the island, you would make an interior ring for the island. - -When defining a ring, you must pick either a clockwise or counterclockwise ordering for your points. The first and last point of the polygon must be the same. - -Currently, we only support unprojected global coordinates (decimal degrees longitude and latitude) and we are datum agnostic. - -```json - -{ - "key": "location", - "geo_polygon": { - "exterior": { - "points": [ - { "lon": -70.0, "lat": -70.0 }, - { "lon": 60.0, "lat": -70.0 }, - { "lon": 60.0, "lat": 60.0 }, - { "lon": -70.0, "lat": 60.0 }, - { "lon": -70.0, "lat": -70.0 } - ] - }, - "interiors": [ - { - "points": [ - { "lon": -65.0, "lat": -65.0 }, - { "lon": 0.0, "lat": -65.0 }, - { "lon": 0.0, "lat": 0.0 }, - { "lon": -65.0, "lat": 0.0 }, - { "lon": -65.0, "lat": -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. -These conditions can only be applied to payloads that match the [geo-data format](../payload/#geo). - -### Values count - -In addition to the direct value comparison, it is also possible to filter by the amount of values. - -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"] } -] -``` - -We can perform the search only among the items with more than two comments: - -```json -{ - "key": "comments", - "values_count": { - "gt": 2 - } -} -``` - -The result would be: - -```json -[{ "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. - -### Is Empty - -Sometimes it is also useful to filter out records that are missing some value. -The `IsEmpty` condition may help you with that: - -```json -{ - "is_empty": { - "key": "reports" - } -} -``` - -This condition will match all records where the field `reports` either does not exist, or has `null` or `[]` value. - - - -### Is Null - -It is not possible to test for `NULL` values with the match condition. -We have to use `IsNull` condition instead: - -```json -{ - "is_null": { - "key": "reports" - } -} -``` - -This condition will match all records where the field `reports` exists and has `NULL` value. - - -### Has id - -This type of query is not related to payload, but can be very useful in some situations. -For example, the user could mark some specific search results as irrelevant, or we want to search only among the specified points. - -```json withRunButton=true -POST /collections/demo1/points/scroll - -{ - "filter": { - "must": [ - { "has_id": [1,3,5,7,9,11] } - ] - } - ... -} -``` - -Filtered points would be: - -```json -[ - { "id": 1, "city": "London", "color": "green" }, - { "id": 3, "city": "London", "color": "blue" }, - { "id": 5, "city": "Moscow", "color": "green" } -] -``` diff --git a/src/components/InteractiveTutorial/MdxPages/Index.mdx b/src/components/InteractiveTutorial/MdxPages/Index.mdx index 21909cc0..ebbf3972 100644 --- a/src/components/InteractiveTutorial/MdxPages/Index.mdx +++ b/src/components/InteractiveTutorial/MdxPages/Index.mdx @@ -18,7 +18,6 @@ You also can edit the code blocks and see how the results change. **Table of Contents** - [Quickstart](#/tutorial/quickstart) - [Filtering Clauses](#/tutorial/filtering-clauses) - - [Filtering Conditions](#/tutorial/filtering-conditions)
diff --git a/src/components/InteractiveTutorial/MdxPages/Quickstart.mdx b/src/components/InteractiveTutorial/MdxPages/Quickstart.mdx index 880b41b3..98ff1dec 100644 --- a/src/components/InteractiveTutorial/MdxPages/Quickstart.mdx +++ b/src/components/InteractiveTutorial/MdxPages/Quickstart.mdx @@ -4,7 +4,7 @@ export const title = 'Quickstart'; In this short example, you will create a Collection, load data into it and run a basic search query. -Click RUN button at code blocks to see a result of the query in the right part of the screen. +Click **RUN** button at code blocks to see a result of the query in the right part of the screen.
Click inside a code block to edit it.
## Create a collection diff --git a/src/components/InteractiveTutorial/TutorialSubpages.jsx b/src/components/InteractiveTutorial/TutorialSubpages.jsx index d3417513..1fe55cf6 100644 --- a/src/components/InteractiveTutorial/TutorialSubpages.jsx +++ b/src/components/InteractiveTutorial/TutorialSubpages.jsx @@ -1,7 +1,6 @@ import * as Index from './MdxPages/Index.mdx'; import * as Quickstart from './MdxPages/Quickstart.mdx'; import * as FilteringClauses from './MdxPages/FilteringClauses.mdx'; -import * as FilteringConditions from './MdxPages/FilteringConditions.mdx'; /** * MDX page object (Index etc.) contains: @@ -14,7 +13,6 @@ export const tutorialIndexPage = Index; const tutorialSubPages = [ ['quickstart', Quickstart], ['filtering-clauses', FilteringClauses], - ['filtering-conditions', FilteringConditions], ]; export { tutorialSubPages }; From bc86b730102057ceea12a0133ad941c98f1207ee Mon Sep 17 00:00:00 2001 From: trean Date: Mon, 16 Oct 2023 16:01:07 +0200 Subject: [PATCH 3/6] scroll to top on location change --- .../InteractiveTutorial/InteractiveTutorial.jsx | 12 +++++++++++- .../InteractiveTutorial/TutorialSubpages.jsx | 1 + 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/components/InteractiveTutorial/InteractiveTutorial.jsx b/src/components/InteractiveTutorial/InteractiveTutorial.jsx index 43e3bcd9..ea18e5c4 100644 --- a/src/components/InteractiveTutorial/InteractiveTutorial.jsx +++ b/src/components/InteractiveTutorial/InteractiveTutorial.jsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { useEffect } from "react"; import PropTypes from 'prop-types'; import Box from '@mui/material/Box'; import { alpha } from '@mui/material'; @@ -9,10 +9,19 @@ import { mdxComponents } from './MdxComponents/MdxComponents'; import { useTutorial } from '../../context/tutorial-context'; import { TutorialFooter } from './TutorialFooter'; import { tutorialSubPages, tutorialIndexPage } from './TutorialSubpages'; +import { useLocation } from "react-router-dom"; const InteractiveTutorial = ({ pageSlug }) => { const theme = useTheme(); const { result } = useTutorial(); + const location = useLocation(); + const tutorialPanelRef = React.useRef(null); + + useEffect(() => { + if (tutorialPanelRef.current) { + tutorialPanelRef.current.scrollTop = 0; + } + }, [location]); let TagName; try { @@ -36,6 +45,7 @@ const InteractiveTutorial = ({ pageSlug }) => { bottom: 0, overflowY: 'scroll', }} + ref={tutorialPanelRef} > diff --git a/src/components/InteractiveTutorial/TutorialSubpages.jsx b/src/components/InteractiveTutorial/TutorialSubpages.jsx index 1fe55cf6..4f60466c 100644 --- a/src/components/InteractiveTutorial/TutorialSubpages.jsx +++ b/src/components/InteractiveTutorial/TutorialSubpages.jsx @@ -13,6 +13,7 @@ export const tutorialIndexPage = Index; const tutorialSubPages = [ ['quickstart', Quickstart], ['filtering-clauses', FilteringClauses], + // add more pages here ]; export { tutorialSubPages }; From c96d7a53d124bebc62fc0e30cce606b2062fa9f9 Mon Sep 17 00:00:00 2001 From: trean Date: Tue, 17 Oct 2023 16:18:21 +0200 Subject: [PATCH 4/6] fixes --- .../InteractiveTutorial.jsx | 8 + .../MdxComponents/CodeBlock.jsx | 10 +- .../MdxPages/FilteringClauses.mdx | 171 +++++++++++------- .../MdxPages/Quickstart.mdx | 22 +-- 4 files changed, 127 insertions(+), 84 deletions(-) diff --git a/src/components/InteractiveTutorial/InteractiveTutorial.jsx b/src/components/InteractiveTutorial/InteractiveTutorial.jsx index ea18e5c4..27c9c996 100644 --- a/src/components/InteractiveTutorial/InteractiveTutorial.jsx +++ b/src/components/InteractiveTutorial/InteractiveTutorial.jsx @@ -10,6 +10,7 @@ import { useTutorial } from '../../context/tutorial-context'; import { TutorialFooter } from './TutorialFooter'; import { tutorialSubPages, tutorialIndexPage } from './TutorialSubpages'; import { useLocation } from "react-router-dom"; +import { Prism } from "prism-react-renderer"; const InteractiveTutorial = ({ pageSlug }) => { const theme = useTheme(); @@ -17,6 +18,13 @@ const InteractiveTutorial = ({ pageSlug }) => { const location = useLocation(); const tutorialPanelRef = React.useRef(null); + useEffect(() => { + // we need this to use prismjs support for json highlighting + // which is not included in the prism-react-renderer package by default + window.Prism = Prism; // (or check for window is undefined for ssr and use global) + (async () => await import('prismjs/components/prism-json'))(); + }, []); + useEffect(() => { if (tutorialPanelRef.current) { tutorialPanelRef.current.scrollTop = 0; diff --git a/src/components/InteractiveTutorial/MdxComponents/CodeBlock.jsx b/src/components/InteractiveTutorial/MdxComponents/CodeBlock.jsx index 9181b32a..2f22927b 100644 --- a/src/components/InteractiveTutorial/MdxComponents/CodeBlock.jsx +++ b/src/components/InteractiveTutorial/MdxComponents/CodeBlock.jsx @@ -1,4 +1,4 @@ -import React, { useEffect, useState } from 'react'; +import React, { useState } from 'react'; import PropTypes from 'prop-types'; import { Highlight, Prism, themes } from 'prism-react-renderer'; import Editor from 'react-simple-code-editor'; @@ -30,6 +30,7 @@ const StyledEditor = styled((props) => { const { setResult } = useTutorial(); const handleClick = () => { + setResult('{}'); requestFromCode(code, false) .then((res) => { setResult(() => JSON.stringify(res)); @@ -64,13 +65,6 @@ export const CodeBlock = ({ children }) => { const prismTheme = theme.palette.mode === 'light' ? themes.nightOwlLight : themes.vsDark; const backgroundColor = theme.palette.mode === 'light' ? LIGHT_BACKGROUND : DARK_BACKGROUND; - useEffect(() => { - // we need this to use prismjs support for json highlighting - // which is not included in the prism-react-renderer package by default - window.Prism = Prism; // (or check for window is undefined for ssr and use global) - (async () => await import('prismjs/components/prism-json'))(); - }, []); - const handleChange = (code) => { setCode(() => code); }; diff --git a/src/components/InteractiveTutorial/MdxPages/FilteringClauses.mdx b/src/components/InteractiveTutorial/MdxPages/FilteringClauses.mdx index 14db711a..7f246ae4 100644 --- a/src/components/InteractiveTutorial/MdxPages/FilteringClauses.mdx +++ b/src/components/InteractiveTutorial/MdxPages/FilteringClauses.mdx @@ -18,30 +18,49 @@ Let's start with creating a new collection and populating it with points.
Run these two steps: - 1. Create a collection: - - ```json withRunButton="true" - PUT collections/demo1 - { - "vectors": { - "size": 4, - "distance": "Dot" - } +1. Create a collection: + +``` json withRunButton="true" +PUT collections/demo +{ + "vectors": { + "size": 4, + "distance": "Dot" } - ``` +} +``` 2. And add points to it: -```json withRunButton="true" -PUT /collections/demo1/points +``` json withRunButton="true" +PUT /collections/demo/points { "points": [ - { "id": 1, "vector": [0.1, 0.2, 0.3, 0.4], "payload": { "city": "London", "color": "green" } }, - { "id": 2, "vector": [0.2, 0.3, 0.4, 0.5], "payload": { "city": "London", "color": "red" } }, - { "id": 3, "vector": [0.3, 0.4, 0.5, 0.6], "payload": { "city": "London", "color": "blue" } }, - { "id": 4, "vector": [0.4, 0.5, 0.6, 0.7], "payload": { "city": "Berlin", "color": "red" } }, - { "id": 5, "vector": [0.5, 0.6, 0.7, 0.8], "payload": { "city": "Moscow", "color": "green" } }, - { "id": 6, "vector": [0.6, 0.7, 0.8, 0.9], "payload": { "city": "Moscow", "color": "blue" } } + { + "id": 1, + "vector": [0.1, 0.2, 0.3, 0.4], + "payload": { "city": "London", "color": "green" } + }, { + "id": 2, + "vector": [0.2, 0.3, 0.4, 0.5], + "payload": { "city": "London", "color": "red" } + }, { + "id": 3, + "vector": [0.3, 0.4, 0.5, 0.6], + "payload": { "city": "London", "color": "blue" } + }, { + "id": 4, + "vector": [0.4, 0.5, 0.6, 0.7], + "payload": { "city": "Berlin", "color": "red" } + }, { + "id": 5, + "vector": [0.5, 0.6, 0.7, 0.8], + "payload": { "city": "Moscow", "color": "green" } + }, { + "id": 6, + "vector": [0.6, 0.7, 0.8, 0.9], + "payload": { "city": "Moscow", "color": "blue" } + } ] } ``` @@ -57,15 +76,19 @@ In this sense, `must` is equivalent to the operator `AND`. Run the next example: ``` json withRunButton="true" -POST /collections/demo1/points/scroll - +POST /collections/demo/points/scroll { - "filter": { - "must": [ - { "key": "city", "match": { "value": "London" } }, - { "key": "color", "match": { "value": "red" } } - ] - } + "filter": { + "must": [ + { + "key": "city", + "match": { "value": "London" } + }, { + "key": "color", + "match": { "value": "red" } + } + ] + } } ``` @@ -76,16 +99,20 @@ In this sense, `should` is equivalent to the operator `OR`. Example: -```json withRunButton="true" -POST /collections/demo1/points/scroll - +``` json withRunButton="true" +POST /collections/demo/points/scroll { - "filter": { - "should": [ - { "key": "city", "match": { "value": "London" } }, - { "key": "color", "match": { "value": "red" } } - ] - } + "filter": { + "should": [ + { + "key": "city", + "match": { "value": "London" } + }, { + "key": "color", + "match": { "value": "red" } + } + ] + } } ``` @@ -96,15 +123,20 @@ In this sense, `must_not` is equivalent to the expression `(NOT A) AND (NOT B) A Example: -```json withRunButton="true" -POST /collections/demo1/points/scroll +``` json withRunButton="true" +POST /collections/demo/points/scroll { - "filter": { - "must_not": [ - { "key": "city", "match": { "value": "London" } }, - { "key": "color", "match": { "value": "red" } } - ] - } + "filter": { + "must_not": [ + { + "key": "city", + "match": { "value": "London" } + }, { + "key": "color", + "match": { "value": "red" } + } + ] + } } ``` @@ -112,17 +144,23 @@ POST /collections/demo1/points/scroll It is also possible to use several clauses simultaneously: -```json withRunButton="true" -POST /collections/demo1/points/scroll +``` json withRunButton="true" +POST /collections/demo/points/scroll { - "filter": { - "must": [ - { "key": "city", "match": { "value": "London" } } - ], - "must_not": [ - { "key": "color", "match": { "value": "red" } } - ] - } + "filter": { + "must": [ + { + "key": "city", + "match": { "value": "London" } + } + ], + "must_not": [ + { + "key": "color", + "match": { "value": "red" } + } + ] + } } ``` @@ -130,18 +168,23 @@ In this case, the conditions are combined by `AND`. Also, the conditions could be recursively nested. Example: -```json withRunButton="true" -POST /collections/demo1/points/scroll +``` json withRunButton="true" +POST /collections/demo/points/scroll { - "filter": { - "must_not": [ - { - "must": [ - { "key": "city", "match": { "value": "London" } }, - { "key": "color", "match": { "value": "red" } } - ] - } + "filter": { + "must_not": [ + { + "must": [ + { + "key": "city", + "match": { "value": "London" } + }, { + "key": "color", + "match": { "value": "red" } + } ] - } + } + ] + } } ``` diff --git a/src/components/InteractiveTutorial/MdxPages/Quickstart.mdx b/src/components/InteractiveTutorial/MdxPages/Quickstart.mdx index 98ff1dec..bb12188d 100644 --- a/src/components/InteractiveTutorial/MdxPages/Quickstart.mdx +++ b/src/components/InteractiveTutorial/MdxPages/Quickstart.mdx @@ -84,18 +84,16 @@ We can narrow down the results further by filtering by payload. Let's find the c ```json withRunButton=true POST collections/test_collection/points/search { - "vector": [0.2, 0.1, 0.9, 0.7], - "filter": { - "must": [ - { - "key": "city", - "match": { - "value": "London" - } - } - ] - }, - "limit": 3 + "vector": [0.2, 0.1, 0.9, 0.7], + "filter": { + "must": [ + { + "key": "city", + "match": { "value": "London" } + } + ] + }, + "limit": 3 } ``` From af5150bbcaa1eb06fa6c8279983add4446aeef8f Mon Sep 17 00:00:00 2001 From: trean Date: Tue, 17 Oct 2023 16:39:37 +0200 Subject: [PATCH 5/6] fixes --- package-lock.json | 313 ++++++++++++------ .../InteractiveTutorial.jsx | 6 +- src/components/Sidebar/Sidebar.jsx | 4 +- 3 files changed, 220 insertions(+), 103 deletions(-) diff --git a/package-lock.json b/package-lock.json index 74aa09d8..38f02c20 100644 --- a/package-lock.json +++ b/package-lock.json @@ -108,16 +108,81 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.5.tgz", - "integrity": "sha512-Xmwn266vad+6DAqEB2A6V/CcZVp62BbwVmcOJc2RPuwih1kw02TjQvWVWlcKGbBPd+8/0V5DEkOcizRGYsspYQ==", + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", + "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", "dependencies": { - "@babel/highlight": "^7.22.5" + "@babel/highlight": "^7.22.13", + "chalk": "^2.4.2" }, "engines": { "node": ">=6.9.0" } }, + "node_modules/@babel/code-frame/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/code-frame/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/code-frame/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/code-frame/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "node_modules/@babel/code-frame/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@babel/code-frame/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/code-frame/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/@babel/compat-data": { "version": "7.22.9", "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.22.9.tgz", @@ -156,11 +221,11 @@ } }, "node_modules/@babel/generator": { - "version": "7.21.5", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.21.5.tgz", - "integrity": "sha512-SrKK/sRv8GesIW1bDagf9cCG38IOMYZusoe1dfg0D8aiUe3Amvoj1QtjTPAWcfrZFvIwlleLb0gxzQidL9w14w==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz", + "integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==", "dependencies": { - "@babel/types": "^7.21.5", + "@babel/types": "^7.23.0", "@jridgewell/gen-mapping": "^0.3.2", "@jridgewell/trace-mapping": "^0.3.17", "jsesc": "^2.5.1" @@ -188,20 +253,20 @@ } }, "node_modules/@babel/helper-environment-visitor": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz", - "integrity": "sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-function-name": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz", - "integrity": "sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", "dependencies": { - "@babel/template": "^7.22.5", - "@babel/types": "^7.22.5" + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" }, "engines": { "node": ">=6.9.0" @@ -286,9 +351,9 @@ } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz", - "integrity": "sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", "engines": { "node": ">=6.9.0" } @@ -315,12 +380,12 @@ } }, "node_modules/@babel/highlight": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.5.tgz", - "integrity": "sha512-BSKlD1hgnedS5XRnGOljZawtag7H1yPfQp0tdNJCHoH6AZ+Pcm9VvkrK59/Yy593Ypg0zMxH2BxD1VPYUQ7UIw==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", + "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", "dependencies": { - "@babel/helper-validator-identifier": "^7.22.5", - "chalk": "^2.0.0", + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", "js-tokens": "^4.0.0" }, "engines": { @@ -392,9 +457,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.22.7", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.7.tgz", - "integrity": "sha512-7NF8pOkHP5o2vpmGgNGcfAeCvOYhGLyA3Z4eBQkT1RJlWu47n63bCs93QfJ2hIAFCil7L5P2IWhs1oToVgrL0Q==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz", + "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==", "bin": { "parser": "bin/babel-parser.js" }, @@ -442,31 +507,31 @@ } }, "node_modules/@babel/template": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.5.tgz", - "integrity": "sha512-X7yV7eiwAxdj9k94NEylvbVHLiVG1nvzCV2EAowhxLTwODV1jl9UzZ48leOC0sH7OnuHrIkllaBgneUykIcZaw==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", "dependencies": { - "@babel/code-frame": "^7.22.5", - "@babel/parser": "^7.22.5", - "@babel/types": "^7.22.5" + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.21.5", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.21.5.tgz", - "integrity": "sha512-AhQoI3YjWi6u/y/ntv7k48mcrCXmus0t79J9qPNlk/lAsFlCiJ047RmbfMOawySTHtywXhbXgpx/8nXMYd+oFw==", - "dependencies": { - "@babel/code-frame": "^7.21.4", - "@babel/generator": "^7.21.5", - "@babel/helper-environment-visitor": "^7.21.5", - "@babel/helper-function-name": "^7.21.0", - "@babel/helper-hoist-variables": "^7.18.6", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.21.5", - "@babel/types": "^7.21.5", + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz", + "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==", + "dependencies": { + "@babel/code-frame": "^7.22.13", + "@babel/generator": "^7.23.0", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.23.0", + "@babel/types": "^7.23.0", "debug": "^4.1.0", "globals": "^11.1.0" }, @@ -475,12 +540,12 @@ } }, "node_modules/@babel/types": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.5.tgz", - "integrity": "sha512-zo3MIHGOkPOfoRXitsgHLjEXmlDaD/5KU1Uzuc9GNiZPhSqVxVRtxuPaSBZDsYZ9qV88AjtMtWW7ww98loJ9KA==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", + "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", "dependencies": { "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.20", "to-fast-properties": "^2.0.0" }, "engines": { @@ -8062,11 +8127,63 @@ } }, "@babel/code-frame": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.5.tgz", - "integrity": "sha512-Xmwn266vad+6DAqEB2A6V/CcZVp62BbwVmcOJc2RPuwih1kw02TjQvWVWlcKGbBPd+8/0V5DEkOcizRGYsspYQ==", + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", + "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", "requires": { - "@babel/highlight": "^7.22.5" + "@babel/highlight": "^7.22.13", + "chalk": "^2.4.2" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==" + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==" + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "^3.0.0" + } + } } }, "@babel/compat-data": { @@ -8097,11 +8214,11 @@ } }, "@babel/generator": { - "version": "7.21.5", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.21.5.tgz", - "integrity": "sha512-SrKK/sRv8GesIW1bDagf9cCG38IOMYZusoe1dfg0D8aiUe3Amvoj1QtjTPAWcfrZFvIwlleLb0gxzQidL9w14w==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz", + "integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==", "requires": { - "@babel/types": "^7.21.5", + "@babel/types": "^7.23.0", "@jridgewell/gen-mapping": "^0.3.2", "@jridgewell/trace-mapping": "^0.3.17", "jsesc": "^2.5.1" @@ -8120,17 +8237,17 @@ } }, "@babel/helper-environment-visitor": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz", - "integrity": "sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==" + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==" }, "@babel/helper-function-name": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz", - "integrity": "sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", "requires": { - "@babel/template": "^7.22.5", - "@babel/types": "^7.22.5" + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" } }, "@babel/helper-hoist-variables": { @@ -8188,9 +8305,9 @@ "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==" }, "@babel/helper-validator-identifier": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz", - "integrity": "sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==" + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==" }, "@babel/helper-validator-option": { "version": "7.22.5", @@ -8208,12 +8325,12 @@ } }, "@babel/highlight": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.5.tgz", - "integrity": "sha512-BSKlD1hgnedS5XRnGOljZawtag7H1yPfQp0tdNJCHoH6AZ+Pcm9VvkrK59/Yy593Ypg0zMxH2BxD1VPYUQ7UIw==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", + "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", "requires": { - "@babel/helper-validator-identifier": "^7.22.5", - "chalk": "^2.0.0", + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", "js-tokens": "^4.0.0" }, "dependencies": { @@ -8269,9 +8386,9 @@ } }, "@babel/parser": { - "version": "7.22.7", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.7.tgz", - "integrity": "sha512-7NF8pOkHP5o2vpmGgNGcfAeCvOYhGLyA3Z4eBQkT1RJlWu47n63bCs93QfJ2hIAFCil7L5P2IWhs1oToVgrL0Q==" + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz", + "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==" }, "@babel/plugin-transform-react-jsx-self": { "version": "7.21.0", @@ -8298,39 +8415,39 @@ } }, "@babel/template": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.5.tgz", - "integrity": "sha512-X7yV7eiwAxdj9k94NEylvbVHLiVG1nvzCV2EAowhxLTwODV1jl9UzZ48leOC0sH7OnuHrIkllaBgneUykIcZaw==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", "requires": { - "@babel/code-frame": "^7.22.5", - "@babel/parser": "^7.22.5", - "@babel/types": "^7.22.5" + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" } }, "@babel/traverse": { - "version": "7.21.5", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.21.5.tgz", - "integrity": "sha512-AhQoI3YjWi6u/y/ntv7k48mcrCXmus0t79J9qPNlk/lAsFlCiJ047RmbfMOawySTHtywXhbXgpx/8nXMYd+oFw==", - "requires": { - "@babel/code-frame": "^7.21.4", - "@babel/generator": "^7.21.5", - "@babel/helper-environment-visitor": "^7.21.5", - "@babel/helper-function-name": "^7.21.0", - "@babel/helper-hoist-variables": "^7.18.6", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.21.5", - "@babel/types": "^7.21.5", + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz", + "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==", + "requires": { + "@babel/code-frame": "^7.22.13", + "@babel/generator": "^7.23.0", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.23.0", + "@babel/types": "^7.23.0", "debug": "^4.1.0", "globals": "^11.1.0" } }, "@babel/types": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.5.tgz", - "integrity": "sha512-zo3MIHGOkPOfoRXitsgHLjEXmlDaD/5KU1Uzuc9GNiZPhSqVxVRtxuPaSBZDsYZ9qV88AjtMtWW7ww98loJ9KA==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", + "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", "requires": { "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.20", "to-fast-properties": "^2.0.0" } }, diff --git a/src/components/InteractiveTutorial/InteractiveTutorial.jsx b/src/components/InteractiveTutorial/InteractiveTutorial.jsx index 27c9c996..922a5db3 100644 --- a/src/components/InteractiveTutorial/InteractiveTutorial.jsx +++ b/src/components/InteractiveTutorial/InteractiveTutorial.jsx @@ -1,4 +1,4 @@ -import React, { useEffect } from "react"; +import React, { useEffect } from 'react'; import PropTypes from 'prop-types'; import Box from '@mui/material/Box'; import { alpha } from '@mui/material'; @@ -9,8 +9,8 @@ import { mdxComponents } from './MdxComponents/MdxComponents'; import { useTutorial } from '../../context/tutorial-context'; import { TutorialFooter } from './TutorialFooter'; import { tutorialSubPages, tutorialIndexPage } from './TutorialSubpages'; -import { useLocation } from "react-router-dom"; -import { Prism } from "prism-react-renderer"; +import { useLocation } from 'react-router-dom'; +import { Prism } from 'prism-react-renderer'; const InteractiveTutorial = ({ pageSlug }) => { const theme = useTheme(); diff --git a/src/components/Sidebar/Sidebar.jsx b/src/components/Sidebar/Sidebar.jsx index a07f5aa8..8a0024be 100644 --- a/src/components/Sidebar/Sidebar.jsx +++ b/src/components/Sidebar/Sidebar.jsx @@ -111,9 +111,9 @@ export default function Sidebar({ open, version }) { - + - + From ed945e24ca30de10b1164c8429f7ff1f609b39f1 Mon Sep 17 00:00:00 2001 From: generall Date: Mon, 30 Oct 2023 16:48:39 +0100 Subject: [PATCH 6/6] update for tutorial text --- .../MdxPages/FilteringClauses.mdx | 2 ++ .../InteractiveTutorial/MdxPages/Index.mdx | 13 ++++++++----- .../InteractiveTutorial/MdxPages/Quickstart.mdx | 12 +++++------- 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/src/components/InteractiveTutorial/MdxPages/FilteringClauses.mdx b/src/components/InteractiveTutorial/MdxPages/FilteringClauses.mdx index 7f246ae4..0867b210 100644 --- a/src/components/InteractiveTutorial/MdxPages/FilteringClauses.mdx +++ b/src/components/InteractiveTutorial/MdxPages/FilteringClauses.mdx @@ -15,6 +15,8 @@ Let's start with creating a new collection and populating it with points. ## Set up for this tutorial +Before we start to practice with filtering conditions, let's create some datapoints to work with. +
Run these two steps: diff --git a/src/components/InteractiveTutorial/MdxPages/Index.mdx b/src/components/InteractiveTutorial/MdxPages/Index.mdx index ebbf3972..62ef35cf 100644 --- a/src/components/InteractiveTutorial/MdxPages/Index.mdx +++ b/src/components/InteractiveTutorial/MdxPages/Index.mdx @@ -1,15 +1,18 @@ # Interactive Tutorial -## What is Qdrant? +## How to run Qdrant? -Qdrant “is a vector similarity search engine that provides a production-ready service with a convenient API to store, search, and manage points (i.e. vectors) with an additional payload.” -You can think of the payloads as additional pieces of information that can help you hone in on your search and also receive useful information that you can give to your users. +If you are reading this, you probably already have Qdrant running! +All the examples in this tutorial do not require any additional setup from your side. -You can get started using Qdrant with the Python qdrant-client, by pulling the latest docker image of qdrant and connecting to it locally, or by trying out Qdrant’s Cloud free tier option until you are ready to make the full switch. +This tutorial will demonstrate principles of Qdrant API, which you would be able to reproduce in +Qdrant UI or in Qdrant client for your [favorite programming language](https://qdrant.tech/documentation/interfaces/). ## What is a interactive tutorial? -In this tutorial, we will guide you through using Qdrant to search for vectors similar to a given vector. +In this tutorial, we will guide you through Qdrant API step by step. +You will explore the main features and learn core concepts of Qdrant on an interactive examples. + You will be able to run the code blocks in this tutorial and see the results in real-time. You also can edit the code blocks and see how the results change. diff --git a/src/components/InteractiveTutorial/MdxPages/Quickstart.mdx b/src/components/InteractiveTutorial/MdxPages/Quickstart.mdx index bb12188d..2e62b136 100644 --- a/src/components/InteractiveTutorial/MdxPages/Quickstart.mdx +++ b/src/components/InteractiveTutorial/MdxPages/Quickstart.mdx @@ -70,7 +70,8 @@ Let's ask a basic question - Which of our stored vectors are most similar to the POST collections/test_collection/points/search { "vector": [0.2, 0.1, 0.9, 0.7], - "limit": 3 + "limit": 3, + "with_payload": true } ``` @@ -93,7 +94,8 @@ POST collections/test_collection/points/search } ] }, - "limit": 3 + "limit": 3, + "with_payload": true } ``` @@ -101,8 +103,4 @@ You have just conducted vector search. You loaded vectors into a database and qu ## Next steps -Now you know how Qdrant works. Getting started with [Qdrant Cloud](https://qdrant.tech/documentation/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](https://qdrant.tech/documentation/tutorials/) and create your own app with the help of our [Examples](https://qdrant.tech/documentation/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. +In the next section, you will learn how to create complex filter conditions and how to use them in your queries. \ No newline at end of file