Skip to main content

Search

This page covers every way to read and prune data in a VectorDB index: similarity queries, payload filters, score thresholds, paging through raw points, and deleting points. Each pattern comes with a runnable request and its expected output.

All examples assume the setup from the quickstart:

export VDB="$CAI_VECTORDB_API"
export TOKEN="$CAI_TOKEN"
export PROJECT="00000000-0000-0000-0000-000000000000" # your project UUID

and an index named docs with 4 dimensions containing:

{"points":[
{"id":1,"vector":[0.1,0.2,0.3,0.4],"payload":{"tag":"alpha"}},
{"id":2,"vector":[0.9,0.8,0.7,0.6],"payload":{"tag":"beta"}}]}

A query takes a vector and returns the points closest to it, best first. This is called ANN searchapproximate nearest neighbor — "approximate" because the engine uses a smart shortcut structure instead of comparing your query against every stored vector, trading a tiny bit of accuracy for a lot of speed.

curl -sX POST "$VDB/v1/projects/$PROJECT/indexes/docs:query" \
-H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
-d '{"vector":[0.1,0.2,0.3,0.4],"top_k":5}'

You should see:

{"index":"docs","results":[{"id":1,"score":1.0,"payload":{"tag":"alpha"}},{"id":2,"score":...,"payload":{"tag":"beta"}}]}

Request fields

FieldTypeDefaultNotes
vectorarray of numbersrequiredMust match the index's dimensions exactly
top_kinteger10How many nearest points to return; max 1000
filterJSON objectnonePayload filter (below); max 64 KiB
with_payloadbooleantrueInclude each hit's payload
with_vectorbooleanfalseInclude each hit's stored vector
score_thresholdnumbernoneDrop hits scoring below this value
offsetinteger0Skip the first N hits (must not be negative)

Scores

Every hit carries a score computed with the index's distance metric. Results are ordered best first. With cosine, an identical vector scores a perfect 1.0 — which is why the quickstart's exact-match query returns "score":1.0. Use score_threshold to cut off weak matches instead of post-filtering client-side:

curl -sX POST "$VDB/v1/projects/$PROJECT/indexes/docs:query" \
-H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
-d '{"vector":[0.1,0.2,0.3,0.4],"top_k":10,"score_threshold":0.9}'

You should see only the strong match:

{"index":"docs","results":[{"id":1,"score":1.0,"payload":{"tag":"alpha"}}]}

Payload filters

A filter restricts search to points whose payload matches a condition — "nearest neighbors, but only among documents tagged alpha". Filters use the Qdrant filter syntax: a JSON object with clauses like must containing conditions that pair a payload key with a match:

curl -sX POST "$VDB/v1/projects/$PROJECT/indexes/docs:query" \
-H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
-d '{"vector":[0.5,0.5,0.5,0.5],"top_k":5,
"filter":{"must":[{"key":"tag","match":{"value":"beta"}}]}}'

You should see:

{"index":"docs","results":[{"id":2,"score":...,"payload":{"tag":"beta"}}]}

Filter rules:

  • The filter must be a JSON object (400 filter must be a JSON object).
  • It is capped at 64 KiB (400 filter is too large).
  • Filter mistakes the engine itself rejects come back as 400 vector database rejected the request: <engine message> — the engine's own explanation is passed through verbatim so you can fix the actual problem.

Browsing without a query: scroll

Scroll lists points in id order — no vector needed. It's the "just show me what's in here" operation, and it's what the console's Data browser uses.

curl -sX POST "$VDB/v1/projects/$PROJECT/indexes/docs:scroll" \
-H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
-d '{"limit":50}'

You should see:

{"index":"docs","points":[{"id":1,"payload":{"tag":"alpha"}},{"id":2,"payload":{"tag":"beta"}}],"next_offset":...}
  • limit defaults to 50, max 1000 (400 limit must be at most 1000).
  • Scrolled points carry payloads but never vectors.
  • Pagination: when there are more points, the response includes next_offset (a point id). Send it back as offset in your next request. When next_offset is absent, you've seen everything. Sending a malformed offset gets 400 offset must be an unsigned integer or a UUID string.

Deleting points

Delete by explicit ids or by filter — exactly one of the two:

curl -sX POST "$VDB/v1/projects/$PROJECT/indexes/docs:delete-points" \
-H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
-d '{"ids":[1]}'

You should see:

{"index":"docs","status":"ok","ids_requested":1}

Or by filter:

curl -sX POST "$VDB/v1/projects/$PROJECT/indexes/docs:delete-points" \
-H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
-d '{"filter":{"must":[{"key":"tag","match":{"value":"beta"}}]}}'

You should see:

{"index":"docs","status":"ok"}

Rules:

  • Provide exactly one of ids or filter (400 provide exactly one of ids or filter).
  • At most 1000 ids per request (400 at most 1000 ids per request).
  • An empty filter is deliberately refused, because it would match everything:
{"error":"an empty filter would delete every point; delete the index instead if that is the intent","request_id":"..."}

Common errors at a glance

Symptom (verbatim error)CauseFix
index is not ready yet; its collection has not been createdQuerying right after createPoll GET .../indexes/{name} until ready: true
query vector has N dimensions; index "docs" expects MQuery vector from the wrong embedding modelEmbed queries with the same model you indexed with
top_k must be at most 1000Asking for too many resultsPage with offset, or rethink why you need 1000+ neighbors
filter is too largeFilter over 64 KiBSimplify the filter; move logic into payload design
offset must not be negativeNegative offset in a queryUse 0 or a positive integer

Trying queries in the console

Each index's detail page in the console (Data services → VectorDB → your index) has a Query panel: paste a vector (JSON array or comma/space-separated numbers), set Top K and an optional payload filter, and use the "Fill with a random vector" button for a quick smoke test. The Data browser tab walks scroll pages and offers per-point delete.

Next steps