Skip to main content
Applies to: Embedded ❌, Enterprise ✅ Full-text search is a table function, fts(table, query), rather than a predicate: it produces a relevance score alongside the matching rows, and a WHERE clause has nowhere to put one. The two string-literal arguments are the table name and a JSON-encoded query, built with the same query-builder classes used from the SDK and serialized with .to_json().

Setup

Run these statements in order, sending one statement per SQL request. Semicolons separate the statements for clients that execute a script.
Phrase queries need position information, which costs extra index size. Add WITH (with_position = true) to CREATE INDEX. Without it, phrase queries find nothing. See FTS parameters.

Basic search

The query builder produces the JSON string used as the second SQL argument. The SQL examples below spell out the equivalent match object so they can be run directly after the setup above.
By default the top 5 matches come back in arbitrary order. Select _score and order by it for relevance ranking:
_score is a pseudo-column carrying the query’s BM25 relevance for the row; it behaves like any other column, but exists only in a relation that came from fts(). See Data types.

Fuzzy

Tolerates typos, up to a character-edit budget:

Phrase

Exact phrase, or with slop to allow words between terms:

Boolean

Combine queries with & (AND) or | (OR):

Boost

Weight a query up or down relative to another:

Multi-match

Search several columns at once, optionally weighting them differently:

Combining with SQL

fts() is a relation, so it composes with the rest of the SQL surface. Filter, join, or aggregate over it same as any table:

What to read next

Full-Text Search

The query-builder equivalent, and every query form in full.

FTS Index

Tokenizers, and the position information phrase queries need.