Skip to main content
Indexes a text or citext column (or a text-producing expression) for TINQL search, including phrases, proximity, and spans. Documents and queries are analyzed with the same tokenization pipeline. Each TIN index covers one text source. Multi-column USING tin (…) indexes are not supported. To search several columns, create one TIN index per column and combine ==> predicates. tin.score(ctid) combines relevance across those columns.

Partial and expression indexes

Partial and expression TIN indexes work like other Postgres index types:
The query must match the indexed expression exactly. (data->>'title') ==> … uses the expression index, and a plain title ==> … does not. A partial index is used only when Postgres can prove the query implies its WHERE predicate (for example WHERE active AND body ==> …).

Index options (WITH)

Scoring

Scoring options are read at query time, so ALTER INDEX ... SET takes effect on the next scored query without a rebuild. k1 and b can also be overridden for a single query with tin.score(ctid, k1 => …, b => …). tin.score_inspect shows which terms a query would score after stop words and dense-term elision are applied.

Tokenization

Defaults fold case and accents, split over-long tokens on grapheme boundaries, and emit emoji as searchable terms. Indexing and query analysis use the same pipeline, so ==> searches agree with what the index stored.
Use tin.tokenize to inspect the pipeline. Named arguments match the index options and use the same defaults:
Hyphenated surface forms may still split into multiple tokens (for example wi-fi becomes the phrase "wi fi"). Fuzzy (term~N) requires a single token after tokenization. Changing tokenization options on a populated index does not re-tokenize stored rows. Run REINDEX to apply the new policy to them.

Segments

A TIN index is stored as segments. The segment count sets how many parallel workers a build and a query can use, and background maintenance folds new writes into segments over time. Changes to these options take effect on the next maintenance pass, except initial_segment_count, which is read only at build.

Need help?

Get help from the PlanetScale Support team, or join our Discord community to see how others are using PlanetScale.