Skip to content
Discord Get Started

Full-Text Search

DB9 supports full-text search with language-specific tokenizers.

TokenizerAliasesDescription
jiebachinese, zhparserChinese word segmentation (jieba-rs)
chinese_ngramzhparser_ngramChinese + bigram overlay for multi-char words
simple-Whitespace tokenizer for English/Latin. No stemming, no stopword removal
english-Whitespace tokenizer plus a minimal stopword list (a, an, is, the). No stemming
english_stem-Snowball stemming plus the full PostgreSQL English stopword list (~174 words)

The default configuration is simple (SHOW default_text_search_config). Any other configuration name — including french, german, and spanish — raises unknown text search configuration.

GIN (Generalized Inverted Index) indexes are the standard way to accelerate full-text search queries. Create a GIN index on a tsvector column or expression to avoid sequential scans:

SQL
-- Index on a tsvector column
CREATE INDEX idx_tsv ON documents USING GIN (tsv);
-- Index on an expression
CREATE INDEX idx_content_fts ON documents
USING GIN (to_tsvector('simple', content));

The optimizer uses GIN indexes automatically when the @@ operator matches an indexed expression.

SQL
-- Create index
CREATE INDEX idx_content_fts ON documents
USING gin(to_tsvector('jieba', content));
-- Search
SELECT * FROM documents
WHERE to_tsvector('jieba', content) @@ plainto_tsquery('jieba', '关键词');

Use simple for exact-token matching, or english_stem when you want stemming and stopword removal (the closest match to PostgreSQL’s english configuration):

SQL
-- Exact tokens (no stemming)
CREATE INDEX idx_content_fts ON documents
USING gin(to_tsvector('simple', content));
SELECT * FROM documents
WHERE to_tsvector('simple', content) @@ to_tsquery('simple', 'keyword');
-- Stemmed search: a query for 'running' also matches 'runs'
CREATE INDEX idx_content_stem ON documents
USING gin(to_tsvector('english_stem', content));
SELECT * FROM documents
WHERE to_tsvector('english_stem', content) @@ plainto_tsquery('english_stem', 'running');

Use the same configuration on both sides of @@ and in the index expression. The configurations tokenize differently, so mixing them (for example indexing with simple but querying with english_stem) changes which rows match.

SQL
SELECT
content,
ts_rank(to_tsvector('jieba', content), plainto_tsquery('jieba', '搜索词')) as rank
FROM (VALUES
('全文搜索词法分析很重要'),
('数据库支持中文检索'),
('这段文字没有关键内容')
) AS d(content)
WHERE to_tsvector('jieba', content) @@ plainto_tsquery('jieba', '搜索词')
ORDER BY rank DESC
LIMIT 10;
FunctionDescriptionExample
plainto_tsquerySimple phraseplainto_tsquery('jieba', '人工智能')
to_tsqueryBoolean operatorsto_tsquery('simple', 'cat & dog')
phraseto_tsqueryExact phrasephraseto_tsquery('simple', 'hello world')
websearch_to_tsqueryGoogle-stylewebsearch_to_tsquery('simple', '"exact" -exclude')
SQL
-- AND: both terms must match
SELECT * FROM documents
WHERE tsv @@ to_tsquery('simple', 'database & performance');
-- OR: either term matches
SELECT * FROM documents
WHERE tsv @@ to_tsquery('simple', 'postgres | mysql');
-- NOT: exclude term
SELECT * FROM documents
WHERE tsv @@ to_tsquery('simple', 'database & !oracle');
-- Prefix matching
SELECT * FROM documents
WHERE tsv @@ to_tsquery('simple', 'data:*');
SQL
SELECT
ts_headline('jieba', content, plainto_tsquery('jieba', '数据库'),
'StartSel=<b>, StopSel=</b>, MaxWords=50'
) as highlighted
FROM (VALUES ('数据库支持中文全文检索')) AS d(content)
WHERE to_tsvector('jieba', content) @@ plainto_tsquery('jieba', '数据库');
SQL
-- Prioritize title matches over body
ALTER TABLE articles ADD COLUMN tsv tsvector;
UPDATE articles SET tsv =
setweight(to_tsvector('jieba', title), 'A') ||
setweight(to_tsvector('jieba', body), 'B');
-- Search with weighted ranking
WITH q AS (SELECT plainto_tsquery('jieba', '搜索词') AS query)
SELECT a.title, ts_rank(a.tsv, q.query) AS rank
FROM articles a, q
WHERE a.tsv @@ q.query
ORDER BY rank DESC;
LimitValue
Max tsvector value size1 MB
Max lexemes per tsvector~264,000
Supported text search configurations5 (jieba, chinese_ngram, simple, english, english_stem), plus the aliases chinese, zhparser, zhparser_ngram
GIN index build strategySequential (full table scan)

See Limits and Quotas for the complete list.