--- title: Points weight: 40 aliases: - ../points --- # Points The points are the central entity that Qdrant operates with. A point is a record consisting of a vector and an optional [payload](../payload). You can search among the points grouped in one [collection](../collections) based on vector similarity. This procedure is described in more detail in the [search](../search) and [filtering](../filtering) sections. This section explains how to create and manage vectors. Any point modification operation is asynchronous and takes place in 2 steps. At the first stage, the operation is written to the Write-ahead-log. After this moment, the service will not lose the data, even if the machine loses power supply. ## Awaiting result If the API is called with the `&wait=false` parameter, or if it is not explicitly specified, the client will receive an acknowledgment of receiving data: ```json { "result": { "operation_id": 123, "status": "acknowledged" }, "status": "ok", "time": 0.000206061 } ``` This response does not yet mean that the data is available for retrieval, as it is only added to the collection in the second step. Actual addition to the collection happens in the background, and if you are doing initial vector loading, we recommend using asynchronous requests to take advantage of pipelining. If the logic of your application requires a guarantee that the vector will be available for searching immediately after the API execution, then use the flag `?wait=true`. In this case, the API will return the result only after the operation is finished: ```json { "result": { "operation_id": 0, "status": "completed" }, "status": "ok", "time": 0.000206061 } ``` ## Point IDs Qdrant supports using both `64-bit unsigned integers` and `UUID` as identifiers for points. Examples of UUID string representations: * simple: `936DA01F9ABD4d9d80C702AF85C822A8` * hyphenated: `550e8400-e29b-41d4-a716-446655440000` * urn: `urn:uuid:F9168C5E-CEB2-4faa-B6BF-329BF39FA1E4` That means that in every request UUID string could be used instead of numerical id. Example: ```http PUT /collections/{collection_name}/points { "points": [ { "id": "5c56c793-69f3-4fbf-87e6-c4bf54c28c26", "payload": {"color": "red"}, "vector": [0.9, 0.1, 0.1] } ] } ``` ```python from qdrant_client import QdrantClient from qdrant_client.http import models client = QdrantClient("localhost", port=6333) client.upsert( collection_name="{collection_name}", points=[ models.PointStruct( id="5c56c793-69f3-4fbf-87e6-c4bf54c28c26", payload={ "color": "red", }, vector=[0.9, 0.1, 0.1], ), ] ) ``` and ```http PUT /collections/{collection_name}/points { "points": [ { "id": 1, "payload": {"color": "red"}, "vector": [0.9, 0.1, 0.1] } ] } ``` ```python client.upsert( collection_name="{collection_name}", points=[ models.PointStruct( id=1, payload={ "color": "red", }, vector=[0.9, 0.1, 0.1], ), ] ) ``` are both possible. ## Upload points To optimize performance, Qdrant supports batch loading of points. I.e., you can load several points into the service in one API call. Batching allows you to minimize the overhead of creating a network connection. The Qdrant API supports two ways of creating batches - record-oriented and column-oriented. Internally, these options do not differ and are made only for the convenience of interaction. Create points with REST API : ```http PUT /collections/{collection_name}/points { "batch": { "ids": [1, 2, 3], "payloads": [ {"color": "red"}, {"color": "green"}, {"color": "blue"} ], "vectors": [ [0.9, 0.1, 0.1], [0.1, 0.9, 0.1], [0.1, 0.1, 0.9] ] } } ``` ```python client.upsert( collection_name="{collection_name}", points=models.Batch( ids=[1, 2, 3], payloads=[ {"color": "red"}, {"color": "green"}, {"color": "blue"}, ], vectors=[ [0.9, 0.1, 0.1], [0.1, 0.9, 0.1], [0.1, 0.1, 0.9], ] ), ) ``` or record-oriented equivalent: ```http PUT /collections/{collection_name}/points { "points": [ { "id": 1, "payload": {"color": "red"}, "vector": [0.9, 0.1, 0.1] }, { "id": 2, "payload": {"color": "green"}, "vector": [0.1, 0.9, 0.1] }, { "id": 3, "payload": {"color": "blue"}, "vector": [0.1, 0.1, 0.9] } ] } ``` ```python client.upsert( collection_name="{collection_name}", points=[ models.PointStruct( id=1, payload={ "color": "red", }, vector=[0.9, 0.1, 0.1], ), models.PointStruct( id=2, payload={ "color": "green", }, vector=[0.1, 0.9, 0.1], ), models.PointStruct( id=3, payload={ "color": "blue", }, vector=[0.1, 0.1, 0.9], ), ] ) ``` All APIs in Qdrant, including point loading, are idempotent. It means that executing the same method several times in a row is equivalent to a single execution. In this case, it means that points with the same id will be overwritten when re-uploaded. Idempotence property is useful if you use, for example, a message queue that doesn't provide an exactly-ones guarantee. Even with such a system, Qdrant ensures data consistency. *Available as of v0.10.0* If the collection was created with multiple vectors, each vector data can be provided using the vector's name: ```http PUT /collections/{collection_name}/points { "points": [ { "id": 1, "vector": { "image": [0.9, 0.1, 0.1, 0.2], "text": [0.4, 0.7, 0.1, 0.8, 0.1, 0.1, 0.9, 0.2] } }, { "id": 2, "vector": { "image": [0.2, 0.1, 0.3, 0.9], "text": [0.5, 0.2, 0.7, 0.4, 0.7, 0.2, 0.3, 0.9] } } ] } ``` ```python client.upsert( collection_name="{collection_name}", points=[ models.PointStruct( id=1, vector={ "image": [0.9, 0.1, 0.1, 0.2], "text": [0.4, 0.7, 0.1, 0.8, 0.1, 0.1, 0.9, 0.2], }, ), models.PointStruct( id=2, vector={ "image": [0.2, 0.1, 0.3, 0.9], "text": [0.5, 0.2, 0.7, 0.4, 0.7, 0.2, 0.3, 0.9], }, ), ] ) ``` *Available as of v1.2.0* Named vectors are optional. When uploading points, some vectors may be omitted. For example, you can upload one point with only the `image` vector and a second one with only the `text` vector. When uploading a point with an existing ID, the existing point is deleted first, then it is inserted with just the specified vectors. In other words, the entire point is replaced, and any unspecified vectors are set to null. To keep existing vectors unchanged and only update specified vectors, see [update vectors](#update-vectors). ## Modify points To change a point, you can modify its vectors or its payload. There are several ways to do this. ### Update vectors *Available as of v1.2.0* This method updates the specified vectors on the given points. Unspecified vectors are kept unchanged. All given points must exist. REST API ([Schema](https://qdrant.github.io/qdrant/redoc/index.html#operation/update_vectors)): ```http PUT /collections/{collection_name}/points/vectors { "points": [ { "id": 1, "vector": { "image": [0.1, 0.2, 0.3, 0.4] } }, { "id": 2, "vector": { "text": [0.9, 0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2] } } ] } ``` ```python client.update_vectors( collection_name="{collection_name}", points=[ models.PointStruct( id=1, vector={ "image": [0.1, 0.2, 0.3, 0.4], }, ), models.PointStruct( id=2, vector={ "text": [0.9, 0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2], }, ), ] ) ``` To update points and replace all of its vectors, see [uploading points](#upload-points). ### Delete vectors *Available as of v1.2.0* This method deletes just the specified vectors from the given points. Other vectors are kept unchanged. Points are never deleted. REST API ([Schema](https://qdrant.github.io/qdrant/redoc/index.html#operation/deleted_vectors)): ```http POST /collections/{collection_name}/points/vectors/delete { "points": [0, 3, 100], "vectors": ["text", "image"] } ``` ```python client.delete_vectors( collection_name="{collection_name}", points_selector=models.PointIdsList( points=[0, 3, 100], ), vectors=["text", "image"] ) ``` To delete entire points, see [deleting points](#delete-points). ### Set payload REST API ([Schema](https://qdrant.github.io/qdrant/redoc/index.html#operation/set_payload)): ```http POST /collections/{collection_name}/points/payload { "payload": { "property1": "string", "property2": "string" }, "points": [ 0, 3, 100 ] } ``` ```python client.set_payload( collection_name="{collection_name}", payload={ "property1": "string", "property2": "string", }, points=[0, 3, 10], ) ``` You don't need to know the ids of the points you want to modify. The alternative is to use filters. ```http POST /collections/{collection_name}/points/payload { "payload": { "property1": "string", "property2": "string" }, "filter": { "must": [ { "key": "color", "match": { "value": "red" } } ] } } ``` ```python client.set_payload( collection_name="{collection_name}", payload={ "property1": "string", "property2": "string", }, points=models.Filter( must=[ models.FieldCondition( key="color", match=models.MatchValue(value="red"), ), ], ), ) ``` ### Delete payload keys REST API ([Schema](https://qdrant.github.io/qdrant/redoc/index.html#operation/delete_payload)): ```http POST /collections/{collection_name}/points/payload/delete { "keys": ["color", "price"], "points": [0, 3, 100] } ``` ```python client.delete_payload( collection_name="{collection_name}", keys=["color", "price"], points=[0, 3, 100], ) ``` Alternatively, you can use filters to delete payload keys from the points. ```http POST /collections/{collection_name}/points/payload/delete { "keys": ["color", "price"], "filter": { "must": [ { "key": "color", "match": { "value": "red" } } ] } } ``` ```python client.delete_payload( collection_name="{collection_name}", keys=["color", "price"], points=models.Filter( must=[ models.FieldCondition( key="color", match=models.MatchValue(value="red"), ), ], ), ) ``` ### Clear payload This method removes all payload keys from specified points REST API ([Schema](https://qdrant.github.io/qdrant/redoc/index.html#operation/clear_payload)): ```http POST /collections/{collection_name}/points/payload/clear { "points": [0, 3, 100] } ``` ```python client.clear_payload( collection_name="{collection_name}", points_selector=models.PointIdsList( points=[0, 3, 100], ) ) ``` ## Delete points REST API ([Schema](https://qdrant.github.io/qdrant/redoc/index.html#operation/delete_points)): ```http POST /collections/{collection_name}/points/delete { "points": [0, 3, 100] } ``` ```python client.delete( collection_name="{collection_name}", points_selector=models.PointIdsList( points=[0, 3, 100], ), ) ``` Alternative way to specify which points to remove is to use filter. ```http POST /collections/{collection_name}/points/delete { "filter": { "must": [ { "key": "color", "match": { "value": "red" } } ] } } ``` ```python client.delete( collection_name="{collection_name}", points_selector=models.FilterSelector( filter=models.Filter( must=[ models.FieldCondition( key="color", match=models.MatchValue(value="red"), ), ], ) ), ) ``` This example removes all points with `{ "color": "red" }` from the collection. ## Retrieve points There is a method for retrieving points by their ids. REST API ([Schema](https://qdrant.github.io/qdrant/redoc/index.html#operation/get_points)): ```http POST /collections/{collection_name}/points { "ids": [0, 3, 100] } ``` ```python client.retrieve( collection_name="{collection_name}", ids=[0, 3, 10], ) ``` This method has additional parameters `with_vectors` and `with_payload`. Using these parameters, you can select parts of the point you want as a result. Excluding helps you not to waste traffic transmitting useless data. The single point can also be retrieved via the API: REST API ([Schema](https://qdrant.github.io/qdrant/redoc/index.html#operation/get_point)): ```http GET /collections/{collection_name}/points/{point_id} ``` ## Scroll points Sometimes it might be necessary to get all stored points without knowing ids, or iterate over points that correspond to a filter. REST API ([Schema](https://qdrant.github.io/qdrant/redoc/index.html#operation/scroll_points)): ```http POST /collections/{collection_name}/points/scroll { "filter": { "must": [ { "key": "color", "match": { "value": "red" } } ] }, "limit": 1, "with_payload": true, "with_vector": false } ``` ```python client.scroll( collection_name="{collection_name}", scroll_filter=models.Filter( must=[ models.FieldCondition( key="color", match=models.MatchValue(value="red") ), ] ), limit=1, with_payload=True, with_vectors=False, ) ``` Returns all point with `color` = `red`. ```json { "result": { "next_page_offset": 1, "points": [ { "id": 0, "payload": { "color": "red" } } ] }, "status": "ok", "time": 0.0001 } ``` The Scroll API will return all points that match the filter in a page-by-page manner. All resulting points are sorted by ID. To query the next page it is necessary to specify the largest seen ID in the `offset` field. For convenience, this ID is also returned in the field `next_page_offset`. If the value of the `next_page_offset` field is `null` - the last page is reached. ## Counting points *Available as of v0.8.4* Sometimes it can be useful to know how many points fit the filter conditions without doing a real search. Among others, for example, we can highlight the following scenarios: * Evaluation of results size for faceted search * Determining the number of pages for pagination * Debugging the query execution speed REST API ([Schema](https://qdrant.github.io/qdrant/redoc/index.html#tag/points/operation/count_points)): ```http POST /collections/{collection_name}/points/count { "filter": { "must": [ { "key": "color", "match": { "value": "red" } } ] }, "exact": true } ``` ```python client.count( collection_name="{collection_name}", count_filter=models.Filter( must=[ models.FieldCondition( key="color", match=models.MatchValue(value="red") ), ] ), exact=True, ) ``` Returns number of counts matching given filtering conditions: ```json { "count": 3811 } ```