Prerequisites
- API key — sign in to console.topk.io and generate an API key.
- Region — see docs.topk.io/regions for available regions.
Setup
Connect using any PostgreSQL-compatible client —psql, psycopg2, node-postgres, tokio-postgres, and others.
<region> with your selected region and <api-key> with your API key.
Quick Start
Create a collection, insert documents, and run a semantic search with SQL:The
INDEX clause is a TopK extension to SQL that lets you declare search indexes inline with your column definitions.Schemaless by default
TopK collections are schemaless by default. Documents can have any fields with any types — no schema declaration is required to store or query them. The only exception: fields you want to index must be declared, because index configuration (metric, index type, etc.) is attached to the field definition. For example, to castpublished_year to int4 and rating to float8, use:
SQL Reference
Table references
Statements use<table> as either a collection name or a collection plus partition:
The
schema prefix is accepted but ignored — all collections live in a single namespace per project.Partitions
Partitions can be specified with$ or the PARTITION keyword:
Partition syntax applies to
SELECT, INSERT, UPDATE, and DELETE only. CREATE TABLE and DROP TABLE name collections without partitions; partitions are created implicitly on first write.
SELECT
The primary query interface. Compute search scores in the projection, filter by metadata or text predicates inWHERE, and rank results by any scoring expression in ORDER BY.
OFFSET requires a LIMIT — OFFSET alone is not supported.
Projection
Each item in the select list must be one of:- A named column:
SELECT title, rating - A struct subfield:
SELECT metadata.publisher - An aliased expression:
SELECT rating * 2 AS double_rating— expressions must have anASalias - A search function:
SELECT vector_distance(embedding, '[1,0,0,0]'::f32_vector) AS score - A wire-type cast:
SELECT rating::float8 AS rating_f64
::int4, ::float8, ::text, …) control how the column is typed on the wire, which is useful when your driver infers the wrong type. Unaliased casts use the inner expression as the column name (SELECT title::text → column title). See Output type mapping for the full table.
WHERE filters
match(...) and match_tokens(...) search keyword-indexed text and can be ranked
with bm25_score(). Combine text searches with AND / OR; add metadata filters
with AND:
OR, and with metadata filters using AND.
Search Functions
TopK extends SQL with search-specific functions for scoring and filtering. Scoring functions compute relevance inSELECT; text search predicates filter documents in WHERE.
Scoring functions
Scoring functions compute a relevance score for each document. Call them inSELECT, give them an alias, then use that alias in ORDER BY to rank results. All scoring functions return the score as f32:
Text search predicates
Text search predicates filter documents inWHERE based on keyword matches. match(...) and match_tokens(...) enable BM25 scoring via bm25_score().
match_all(...) and match_any(...) are boolean-only predicates — they filter documents but do not affect relevance ranking:
OR, and with metadata filters using AND:
match(...) and match_tokens(...) cannot be combined with metadata conditions using OR. Use match_any(...) or match_all(...) for keyword predicates that need to appear in an OR alongside other conditions — they work in any logical expression but do not affect bm25_score().Example queries
GROUP BY
Group rows by one or more key expressions and compute aggregations per group.GROUP BY genre) or a SELECT-list alias for a computed expression:
HAVING filters on the grouped/aggregated output and requires a GROUP BY clause:
GROUP BY ALL and ROLLUP / CUBE / GROUPING SETS modifiers are not supported.INSERT
Upsert semantics: inserting a document with an existing_id replaces it.
_id is required and must appear in the column list.
::topk_type casts or constructor
calls — see Type System. Prefer casts in VALUES:
UPDATE
Updates one or more fields on existing documents._id cannot be updated. A WHERE
clause is required and must resolve to a set of document IDs.
Value expressions in SET follow the same rules as INSERT VALUES.
DELETE
Deletes documents by ID or by filter expression. AWHERE clause is required unless
the target is a partition, in which case the entire partition is dropped.
CREATE TABLE
Schema is defined once at collection creation. Indexes are declared inline on each column using a TopK-specificINDEX clause — standalone CREATE INDEX statements are not supported.
IF NOT EXISTS suppresses the error if the collection already exists.Column types
NOT NULL marks a field as required. All columns are optional by default.Index types
Example
DROP TABLE
Permanently deletes a collection and all of its documents and indexes. This operation is irreversible.IF EXISTS suppresses the error if the collection does not exist.information_schema
TopK exposes twoinformation_schema virtual tables for inspecting collections and their schemas. Specify column names explicitly in the select list — SELECT * is not supported on virtual tables.
information_schema.tables
Returns one row per collection in the project. Use it to list collections or check whether a specific collection exists.information_schema.columns
Returns one row per declared field in a collection. Filter by collection name usingWHERE table_name = '<name>'.
Data type mapping:
EXPLAIN
Returns the parsedStatement AST as a single plan TEXT column:
Session commands
SET/SHOW only recognize consistency_level; all other variable names return an error.
The following commands are accepted and silently succeed:
PostgreSQL Compatibility
TopK speaks the PostgreSQL wire protocol but is purpose-built for search — not general-purpose relational queries. Some SQL features are intentionally absent because they don’t map to search semantics or would work against search performance.Queries
SingleORDER BY key — Ranking is a single scoring expression. Combine multiple signals into one composite score rather than sorting by multiple columns: ORDER BY vec_dist * 0.7 + bm25_score() * 0.3 DESC.
No SELECT * — Selecting all columns is not supported. Indexed vector fields cannot be projected directly — use search functions (vector_distance, semantic_similarity, …) to get scores from them instead.
COUNT(*) without GROUP BY is a standalone aggregate — it returns a document count and cannot be combined with other columns in the same SELECT list. Inside a GROUP BY query, COUNT(*) behaves as an ordinary per-group aggregate and can be combined with other keys/aggregates — see GROUP BY.
GROUP BY keys must be identifiers — group by a real column or a SELECT-list alias for a computed expression; you can’t group by an inline expression directly. GROUP BY ALL and ROLLUP/CUBE/GROUPING SETS are not supported.
No whole-value equality on complex types — tags = ARRAY['a'] is not supported. Use contains(tags, 'a') to check whether a single value exists in a list field — contains checks for one value at a time, not a list of values.
Writes
Upsert-onlyINSERT — INSERT always replaces a document when _id already exists, so ON CONFLICT is built-in and not needed. INSERT … SELECT and RETURNING are not supported.
::topk_type casts in VALUES — Standard PostgreSQL casts (::float8, CAST(… AS text)) aren’t supported inside INSERT/UPDATE values. Use TopK-native casts (::f32_vector, ::f32_sparse_vector, …) instead — see Type System.
Transactions
BEGIN/COMMIT/ROLLBACK are accepted without error so that drivers that auto-wrap statements in transactions (psycopg2, SQLAlchemy, JDBC) connect without modification. Writes are not transactional; ROLLBACK does not undo changes.
Structs
Individual struct subfields can be selected using dot notation:Type System
TopK-native literals use::topk_type casts (preferred in INSERT/UPDATE
VALUES and search-function arguments) or equivalent constructor calls.
PostgreSQL wire-type casts (::float8, …) apply only in SELECT projection.
Complex types → JSON
Vector, matrix, sparse, and list types are returned as JSON when selected. Indexed vector fields cannot be projected directly — use scoring functions to compute scores from them. The table below documents the wire format for each type:Output type mapping
pgwire maps SELECT-list expressions to PostgreSQL OIDs. Explicit::cast in the
projection list overrides inference. Casts are stripped from the query plan — they
only affect the wire type.