QUERY is the universal retrieval statement. Pick the expression that matches the input and result shape you need, then apply the same tail clauses for filters, routing, payload selection, and pagination. A top-level query always names its collection with FROM.
Start with a nearest query
Section titled “Start with a nearest query”Use text when an embedder resolves user language at execution time. Use a vector when your application already generated an embedding. QUERY POINT uses a stored point as the similarity input; QUERY POINTS retrieves exact records and does not accept search clauses such as WHERE or LIMIT.
QUERY 'vector database' FROM docs USING dense LIMIT 10;
-- Explicit vector inputQUERY VECTOR [0.1, 0.2, 0.3] FROM docs USING dense LIMIT 10;
-- Implicit vector input (VECTOR keyword is optional for array literals)QUERY [0.1, 0.2, 0.3] FROM docs USING dense LIMIT 10;
QUERY POINT 42 FROM docs USING dense LIMIT 10;
QUERY POINTS (1, 2, 'point-a') FROM docs;TEXT and IMAGE accept an optional MODEL and an opaque OPTIONS dict that passes through to the inference service. OBJECT is the custom inference payload with the same options. Parenthesized OBJECT ({...}) parses but formats to the bare object.
QUERY TEXT 'hi' MODEL 'm' OPTIONS {temperature: 0.5} FROM docs USING dense LIMIT 1;
QUERY IMAGE 'https://x/y.jpg' MODEL 'clip' OPTIONS {size: 512} FROM docs USING img LIMIT 1;
QUERY OBJECT {a: 1} MODEL 'm' OPTIONS {k: true} FROM docs USING dense LIMIT 5;Choose a retrieval strategy
Section titled “Choose a retrieval strategy”| Need | Expression | Why |
|---|---|---|
| Similar documents from one input | QUERY TEXT, VECTOR, or POINT | Standard nearest-neighbor search |
| Combine semantic and lexical candidates | QUERY HYBRID or USING HYBRID | Dense and sparse result sets are fused |
| Bias results toward examples | QUERY RECOMMEND | Positive and negative point IDs define the intent |
| Diversify similar results | QUERY MMR | Re-ranks a candidate set by relevance and diversity |
| Join multiple retrieval stages | CTEs + QUERY FUSION | Explicit prefetch and fusion pipeline |
| Group results by a payload key | GROUP BY | Returns bounded groups rather than a flat list |
Hybrid retrieval
Section titled “Hybrid retrieval”Use the front form when you want the dense and sparse vector names explicit. Use the tail form when schema defaults resolve the names. Both forms are part of the v1 conformance corpus.
QUERY HYBRID TEXT 'vector database' DENSE dense SPARSE sparse FUSION RRFFROM docsLIMIT 10;
QUERY HYBRID TEXT 'search query' FUSION RRF FROM docs LIMIT 10;RRF is a safe default when candidate score scales differ. Choose DBSF when you want distribution-based score normalization. See Hybrid retrieval for multi-stage tuning.
Vector roles in a query target
Section titled “Vector roles in a query target”USING <name> answers which vector; the optional AS <kind> answers what kind of input. The name and the role are independent:
USING <name> [AS DENSE | AS SPARSE | AS MULTI | AS MULTIVECTOR]AS DENSE and AS SPARSE declare the role of the query target: text is then embedded into that role, and a structural vector input must agree with the declaration. AS MULTI and AS MULTIVECTOR are synonyms that mark a dense multivector target (ColBERT-style late interaction) — multivector is not a third kind beside dense and sparse; the role stays dense and text is embedded into [[f32, ...], ...] multi-dense shape. When AS is omitted, the role is resolved from the collection schema at plan time. An explicit structural vector input that contradicts a declared role fails with QQL-PLAN-VECTOR-KIND.
Build an explicit multi-stage pipeline
Section titled “Build an explicit multi-stage pipeline”CTEs make candidate generation visible. A CTE can omit FROM and inherit the outer collection. PREFETCH names must resolve to CTEs.
WITH dense_candidates AS (QUERY 'database internals' USING dense LIMIT 100), sparse_candidates AS (QUERY 'database internals' USING sparse LIMIT 100)QUERY FUSION RRFFROM docsPREFETCH (dense_candidates, sparse_candidates)LIMIT 10;Recommendation, diversity, and groups
Section titled “Recommendation, diversity, and groups”QUERY RECOMMEND POSITIVE (1, 2) NEGATIVE (3) STRATEGY best_scoreFROM productsUSING denseLIMIT 10;
QUERY MMR TEXT 'vector database' DIVERSITY 0.7 CANDIDATES 100FROM docsUSING denseLIMIT 10;DIVERSITY must be between 0 and 1; CANDIDATES must be positive. Use grouping when the UI needs several results per payload category.
QUERY 'incident'FROM runbooksUSING denseGROUP BY service SIZE 3 LOOKUP FROM servicesWITH PAYLOAD INCLUDE (title, service)LIMIT 10;LOOKUP FROM on GROUP BY carries payload and vector selectors for the joined group data. Prefetch LOOKUP FROM additionally routes one leg with an optional vector and shard key.
QUERY 'news'FROM docsGROUP BY topic SIZE 5 LOOKUP FROM topics WITH PAYLOAD INCLUDE (title) WITH VECTOR (dense)LIMIT 20;
WITH a AS (QUERY TEXT 'x' FROM docs USING dense LIMIT 50)QUERY FUSION RRFFROM docsPREFETCH (a LOOKUP FROM docs2 VECTOR dense SHARD 'acme')LIMIT 10;Context, discover, and relevance feedback
Section titled “Context, discover, and relevance feedback”QUERY CONTEXT pairs positive and negative inputs that define a region; QUERY DISCOVER adds a TARGET and shifts results toward it. Each positive/negative/target item is a full query input — use POINT for a point ID, TEXT or VECTOR otherwise.
QUERY CONTEXT (POSITIVE POINT 1 NEGATIVE POINT 2, POSITIVE POINT 3 NEGATIVE POINT 4)FROM docsLIMIT 10;
QUERY DISCOVER TARGET 'search' CONTEXT (POSITIVE POINT 1 NEGATIVE POINT 2)FROM docsLIMIT 10;QUERY RELEVANCE FEEDBACK refines a TARGET with scored feedback pairs and the NAIVE strategy, whose a, b, and c coefficients shape the adjusted query vector. Feedback items pair a query input with a relevance weight.
QUERY RELEVANCE FEEDBACK TARGET 'search' FEEDBACK ((VECTOR [0.1, 0.2], 1.0), (VECTOR [0.3, 0.4], -1.0)) STRATEGY NAIVE (a = 1.0, b = 0.5, c = 0.2)FROM docsLIMIT 10;Order, sample, and fetch exact points
Section titled “Order, sample, and fetch exact points”QUERY ORDER BY sorts by a payload field (ASC or DESC), and QUERY SAMPLE RANDOM draws a random page. Neither expression accepts USING or PREFETCH — there is no similarity input to resolve. ORDER BY accepts an optional START FROM paging origin: an integer, float, datetime string, or placeholder that resumes ordering from that payload value.
QUERY ORDER BY price ASC FROM products WHERE category = 'electronics' LIMIT 10;
QUERY ORDER BY created_at DESC START FROM '2024-01-01T00:00:00Z' FROM docs LIMIT 20;
QUERY SAMPLE RANDOM FROM docs WITH VECTOR false LIMIT 10;QUERY POINTS retrieves exact records by ID and is deliberately minimal: only SHARD, WITH PAYLOAD, and WITH VECTOR clauses are allowed. Filtering, scoring, and paging clauses are invalid — add a WHERE on a QUERY TEXT instead when you need a filtered search.
Rerank candidate lists
Section titled “Rerank candidate lists”QUERY RERANK is late-interaction MaxSim reranking. It always requires USING (a dense or multivector target), a MODEL, and a non-empty PREFETCH.
WITH candidates AS (QUERY 'vector database' USING dense LIMIT 100)QUERY RERANK TEXT 'vector database' MODEL 'reranker-v1'FROM docsUSING colbert AS DENSEPREFETCH (candidates)LIMIT 10;QUERY CROSS RERANK (v1.2) instead scores (query, document text) pairs with a cross-encoder. ON FIELD names the payload key holding document text (default text). It takes no USING vector and requires a host embedder with pair scoring; the scoring runs client-side and reorders the prefetched candidates.
WITH candidates AS (QUERY 'vector database' USING dense LIMIT 100)QUERY CROSS RERANK TEXT 'vector database' MODEL 'bge-reranker-base' ON FIELD abstractFROM docsPREFETCH (candidates)LIMIT 10;Search parameters: sparse IDF corpus
Section titled “Search parameters: sparse IDF corpus”Query-level PARAMS accept search controls such as hnsw_ef, exact, acorn, quantization, timeout, and consistency. For sparse retrieval on Qdrant 1.19+, set a per-query IDF corpus:
| Form | Meaning |
|---|---|
idf = 'global' | Use the collection-wide IDF statistics |
idf = WHERE <filter> | Restrict IDF to points matching that QQL filter |
A malformed idf value fails validation with QQL-VALIDATION-IDF. Isolation stays on statement WHERE / host inject_filter. IDF only scopes BM25 rarity.
QUERY 'search'FROM docsUSING sparsePARAMS (idf = 'global')LIMIT 10;
QUERY 'search'FROM docsUSING sparsePARAMS (idf = WHERE status = 'active')LIMIT 10;
QUERY 'search'FROM docsUSING sparseWHERE tenant_id = 'acme'SHARD 'acme'PARAMS (idf = WHERE tenant_id = 'acme')LIMIT 10;
QUERY 'search'FROM docsUSING sparseWHERE tenant_id = 101SHARD 101PARAMS (idf = WHERE tenant_id = 101)LIMIT 10;Shard keys bind like any other placeholder: SHARD :tenant takes its value from SDK params, with strings routed as keywords and non-negative integers as numbers.
Parameter binding & prepared queries
Section titled “Parameter binding & prepared queries”QQL queries support parameterized templates with type-safe client-side binding:
- Named Placeholders:
:name(e.g.:category,:lim) - Positional Placeholders:
?(mapped sequentially to argument lists)
A template like QUERY TEXT :q FROM docs WHERE category = :cat LIMIT :lim is inert until values are bound — unbound placeholders fail at the plan gate (QQL-BIND-MISSING-PARAM) before any request leaves the client, on every binding path. Here is the same statement with values bound:
QUERY TEXT 'cardiology'FROM docsWHERE category = 'medical'LIMIT 10;Bind client-side with the Python bind / Stmt.bind, Node bind / Stmt.bind, or WASM bind helpers, or pass params straight to Client.execute — see the Python, Node.js, and WebAssembly SDK pages. Rust uses the typed bind_named / bind_positional twins in qql_core::params.
When parameters are bound at runtime via the SDKs (bind or Client.execute(..., params=...)), the template evaluates to a fully-formed, executable QQL statement:
QUERY 'chest pain'FROM docsWHERE category = 'cardiology' AND rating >= 4.5LIMIT 10;Nested dictionaries expand to dotted keys: {"loc": {"lat": 1.0, "lon": 2.0}} binds :loc.lat and :loc.lon, and flat dotted keys work identically. For multi-statement batches, pass params as a list with one entry per statement (the length must match the statement count). Substitution failures carry stable QQL-BIND-* codes — mixed placeholder styles (QQL-BIND-MIXED-STYLE), missing values (QQL-BIND-MISSING-PARAM), extra positional values (QQL-BIND-UNUSED-PARAMS), and type mismatches (QQL-BIND-TYPE-MISMATCH) — see the error code reference.
Colons in compact dictionary syntax (e.g. {a:b}, {'a':b}) are preserved as key-value separators and not treated as placeholders.
For formula scoring and decay functions, continue with Formula scoring.