Skip to content

Syntax Reference

Complete statement reference for the QQL query language.


-- Create
CREATE COLLECTION <name>
CREATE COLLECTION <name> HYBRID
CREATE COLLECTION <name> HYBRID RERANK
CREATE COLLECTION <name> USING MODEL '<model>'
CREATE COLLECTION <name> (name VECTOR(size, DISTANCE), ...)
-- Config
CREATE COLLECTION <name> WITH HNSW (m = 32, ef_construct = 100)
CREATE COLLECTION <name> WITH QUANTIZATION (type = 'scalar', quantile = 0.95)
CREATE COLLECTION <name> WITH QUANTIZATION (type = 'turbo', bits = 2, always_ram = true)
CREATE COLLECTION <name> WITH QUANTIZATION (type = 'binary', always_ram = true)
CREATE COLLECTION <name> WITH QUANTIZATION (type = 'product')
-- Per-vector config
CREATE COLLECTION docs (
dense VECTOR(384, COSINE) WITH QUANTIZATION (type = 'scalar'),
sparse VECTOR(768, DOT)
)
-- Multivector (ColBERT / ColPali) with HNSW disabled for reranking
CREATE COLLECTION docs (
dense VECTOR(384, COSINE),
colbert VECTOR(128, COSINE) WITH MULTIVECTOR (comparator = 'max_sim') WITH HNSW (m = 0)
)
-- PDF retrieval: 3 named vectors (indexed + reranking)
CREATE COLLECTION pdf_retrieval (
original VECTOR(128, COSINE) WITH MULTIVECTOR (comparator = 'max_sim') WITH HNSW (m = 0),
mean_pooling_columns VECTOR(128, COSINE) WITH MULTIVECTOR (comparator = 'max_sim'),
mean_pooling_rows VECTOR(128, COSINE) WITH MULTIVECTOR (comparator = 'max_sim')
)
-- Alter
ALTER COLLECTION <name> WITH VECTORS (on_disk = true)
ALTER COLLECTION <name> WITH HNSW (m = 32)
ALTER COLLECTION <name> WITH OPTIMIZERS (max_segment_size = 500000)
ALTER COLLECTION <name> WITH PARAMS (replication_factor = 3)
ALTER COLLECTION <name> WITH QUANTIZATION (type = 'scalar')
ALTER COLLECTION <name> WITH QUANTIZATION (disabled = true)
-- Drop / Show
DROP COLLECTION <name>
SHOW COLLECTIONS
SHOW COLLECTION <name>

CREATE INDEX ON COLLECTION <name> FOR <field> TYPE keyword
CREATE INDEX ON COLLECTION <name> FOR <field> TYPE integer
CREATE INDEX ON COLLECTION <name> FOR <field> TYPE float
CREATE INDEX ON COLLECTION <name> FOR <field> TYPE bool
CREATE INDEX ON COLLECTION <name> FOR <field> TYPE uuid
CREATE INDEX ON COLLECTION <name> FOR <field> TYPE datetime
CREATE INDEX ON COLLECTION <name> FOR <field> TYPE geo
-- With options
CREATE INDEX ON docs FOR tags TYPE keyword WITH (is_tenant = true, on_disk = true, enable_hnsw = false)
CREATE INDEX ON docs FOR content TYPE text WITH (tokenizer = 'word', min_token_len = 2, max_token_len = 20, lowercase = true, phrase_matching = true, stopwords = ['en'])

INSERT INTO <name> VALUES {'id': 1, 'text': 'hello', 'field': 'value'}
INSERT INTO <name> VALUES {'id': 1, 'text': 'hello'}, {'id': 2, 'text': 'world'}
INSERT INTO <name> VALUES {'id': 1, 'text': 'hello'} USING HYBRID
INSERT INTO <name> VALUES {'id': 1, 'text': 'hello'} USING MODEL '<model>'
INSERT INTO <name> VALUES {'id': 1, 'text': 'hello'} USING HYBRID DENSE MODEL '<m1>' SPARSE MODEL '<m2>'
-- Insert with pre-computed named vectors (dense + multivector)
INSERT INTO docs VALUES {'id': 1, 'text': 'hello', 'vector': {'dense': [0.1, 0.2, 0.3], 'colbert': [[0.1, 0.2], [0.3, 0.4]]}}

Field rules:

  • id — required. Must be an unsigned integer or UUID string.
  • text — required for auto-vectorization.
  • vector — stores pre-computed vectors. Use a map of named vectors for multi-vector collections. Each value can be a 1D array (dense) or 2D array (multivector).

The unified query statement with multiple modes.

QUERY '<text>' FROM <collection> LIMIT <n>
QUERY '<text>' FROM <collection> LIMIT <n> OFFSET <n>
QUERY '<text>' FROM <collection> LIMIT <n> SCORE THRESHOLD 0.5
QUERY '<text>' FROM <collection> LIMIT <n> LOOKUP FROM <other> [VECTOR '<name>']
QUERY '<text>' FROM <collection> LIMIT <n> USING MODEL '<model>'
QUERY [0.1, 0.2, 0.3] FROM <collection> LIMIT <n>
QUERY '<text>' FROM <collection> LIMIT <n> USING HYBRID
QUERY '<text>' FROM <collection> LIMIT <n> USING HYBRID FUSION DBSF
QUERY '<text>' FROM <collection> LIMIT <n> USING HYBRID WITH (rrf_k = 30, rrf_weights = [0.7, 0.3])
QUERY '<text>' FROM <collection> LIMIT <n> USING SPARSE
QUERY '<text>' FROM <collection> LIMIT <n> USING DENSE
QUERY RECOMMEND WITH (positive = ('id-1', 'id-2')) FROM <collection> LIMIT <n>
QUERY RECOMMEND WITH (positive = ('id-1'), negative = ('id-3')) FROM <collection> LIMIT <n>
QUERY RECOMMEND WITH (positive = ('id-1')) STRATEGY 'best_score' FROM <collection> LIMIT <n>

Strategies: average_vector, best_score, sum_scores.

QUERY CONTEXT PAIRS (('id-1', 'id-2'), ('id-3', 'id-4')) FROM <collection> LIMIT <n>
QUERY DISCOVER TARGET 'id-1' CONTEXT PAIRS (('id-2', 'id-3')) FROM <collection> LIMIT <n>
QUERY ORDER BY <field> ASC FROM <collection> LIMIT <n>
QUERY ORDER BY <field> DESC FROM <collection> LIMIT <n>
QUERY SAMPLE FROM <collection> LIMIT <n>
QUERY SAMPLE FROM <collection> LIMIT <n> WHERE <filter>
WITH
dense AS (QUERY [0.1, 0.2, 0.3] USING 'dense' LIMIT 200),
sparse AS (QUERY [0.1, 0.2, 0.3] USING 'sparse' LIMIT 300)
QUERY '<query>' FROM <collection> USING 'colbert' LIMIT 10
PREFETCH (dense, sparse)
-- Per-prefetch filters and score thresholds
WITH
dense AS (QUERY 'search' USING dense LIMIT 200 WHERE category = 'tech'),
sparse AS (QUERY 'search' USING sparse LIMIT 300)
QUERY 'search' FROM <collection> LIMIT 10
PREFETCH (
dense WHERE priority = 'high' SCORE THRESHOLD 0.6,
sparse SCORE THRESHOLD 0.3
)
FUSION RRF WITH (rrf_k = 20, rrf_weights = [0.6, 0.4])
-- Pure fusion (no search target, just fuse CTE results)
FUSION RRF LIMIT 10 PREFETCH (dense, sparse)
-- Pure fusion with CTEs
WITH
_pf0 AS (QUERY 'search' USING 'dense' LIMIT 100),
_pf1 AS (QUERY 'search' USING 'sparse' LIMIT 100)
FUSION RRF LIMIT 10 PREFETCH (_pf0, _pf1)

CTEs can reference previously defined CTEs for nested prefetch DAGs.

ClauseDescription
LIMIT <n>Max results (default 10)
OFFSET <n>Skip first N results
SCORE THRESHOLD <float>Minimum score filter
LOOKUP FROM <col> [VECTOR '<name>']Cross-collection vector lookup
WHERE <filter>Payload filter
USING HYBRIDDense + sparse fusion
USING SPARSESparse-only
USING DENSEDense-only
USING MODEL '<model>'Pin dense model
EXACTExact KNN (no HNSW)
RERANK [MODEL '<model>']Cloud reranking
GROUP BY '<field>' [GROUP_SIZE <n>]Grouped results
WITH LOOKUP FROM <col>Cross-collection group ID lookup
STRATEGY '<strategy>'Recommend strategy
BOOST (<expr>)Score shaping
DEFAULTS (key = value)Formula variable defaults
WITH (hnsw_ef = 256)
WITH (exact = true)
WITH (acorn = true)
WITH (indexed_only = true)
WITH (mmr_diversity = 0.5, mmr_candidates = 20)
WITH (rrf_k = 30, rrf_weights = [0.7, 0.3])
WITH PAYLOAD (include = ['title', 'body'])
WITH PAYLOAD (exclude = ['embedding'])
WITH PAYLOAD false
WITH VECTORS ('dense', 'sparse')
WITH VECTORS true
WITH MODEL '<model>'
WITH LOOKUP FROM <collection>

Multiple WITH clauses merge: WITH MODEL 'x' WITH PAYLOAD (include = ['a']) WITH (exact = true)


QUERY '<text>' FROM <collection> LIMIT <n>
BOOST (<expression>)
DEFAULTS (key = value, ...)
-- Arithmetic
$score * 2 + 1
a + b - c * d / e
a / b [default=1.0] -- division with zero-safety default
-- Math functions
ABS(x) | SQRT(x) | LOG(x) | LN(x) | EXP(x) | POW(base, exponent)
-- Geo distance
GEO_DISTANCE({lat: 40.7, lon: -74.0}, location_field)
-- Decay functions
GAUSS_DECAY(field, target: value, scale: 30d)
EXP_DECAY(field, target: value, scale: 30d)
LIN_DECAY(field, target: value, scale: 30d)
GAUSS_DECAY(field, target: datetime('2026-01-01'), scale: 30d, midpoint: 0.5)
-- Datetime
datetime('2026-01-01T00:00:00Z')
datetime_key('published_at')
-- Conditional
CASE WHEN <filter> THEN <expr> ELSE <expr> END
-- Variables
$score -- current relevance score
field_name -- payload field value

SELECT * FROM <collection> WHERE id = '<uuid>'
SELECT * FROM <collection> WHERE id = <integer>
SCROLL FROM <collection> LIMIT <n>
SCROLL FROM <collection> WHERE <filter> LIMIT <n>
SCROLL FROM <collection> AFTER '<point_id>' LIMIT <n>
SCROLL FROM <collection> WHERE <filter> AFTER <point_id> LIMIT <n>

UPDATE <collection> SET PAYLOAD = {'field': 'value'} WHERE id = '<uuid>'
UPDATE <collection> SET PAYLOAD = {'field': 'value'} WHERE <filter>
UPDATE <collection> SET VECTOR = [0.1, 0.2, 0.3] WHERE id = '<uuid>'
UPDATE <collection> SET VECTOR '<name>' = [0.1, 0.2, 0.3] WHERE id = '<uuid>'

DELETE FROM <collection> WHERE id = '<uuid>'
DELETE FROM <collection> WHERE id = <integer>
DELETE FROM <collection> WHERE <field> = '<value>'
DELETE FROM <collection> WHERE <filter>

EXPLAIN via CLI
qql-go explain "QUERY 'search' FROM docs LIMIT 5 USING HYBRID" qql-go explain --json "QUERY 'search' FROM docs LIMIT 5"

Script execution
qql-go execute <script.qql> qql-go execute --stop-on-error <script.qql> qql-go dump <collection> <output.qql> qql-go dump --batch-size 100 <collection> <output.qql>

Scripts are multi-statement QQL files. Statements are separated by newlines. Comments start with --. No semicolons.


Convert examples
qql-go convert payload.json echo '{"points":[{"id":1,"payload":{"text":"hi"}}]}' | qql-go convert qql-go convert --validate payload.json qql-go convert --json payload.json qql-go convert --quiet payload.json