Full-Text Search
DB9 supports full-text search with language-specific tokenizers.
Available Tokenizers
Section titled “Available Tokenizers”| Tokenizer | Aliases | Description |
|---|---|---|
jieba | chinese, zhparser | Chinese word segmentation (jieba-rs) |
chinese_ngram | zhparser_ngram | Chinese + 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 Indexes for Full-Text Search
Section titled “GIN Indexes for Full-Text Search”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:
-- Index on a tsvector columnCREATE INDEX idx_tsv ON documents USING GIN (tsv);
-- Index on an expressionCREATE INDEX idx_content_fts ON documentsUSING GIN (to_tsvector('simple', content));The optimizer uses GIN indexes automatically when the @@ operator matches an indexed expression.
Chinese Text Search (jieba)
Section titled “Chinese Text Search (jieba)”-- Create indexCREATE INDEX idx_content_fts ON documentsUSING gin(to_tsvector('jieba', content));
-- SearchSELECT * FROM documentsWHERE to_tsvector('jieba', content) @@ plainto_tsquery('jieba', '关键词');English Text Search
Section titled “English Text Search”Use simple for exact-token matching, or english_stem when you want stemming and stopword
removal (the closest match to PostgreSQL’s english configuration):
-- Exact tokens (no stemming)CREATE INDEX idx_content_fts ON documentsUSING gin(to_tsvector('simple', content));
SELECT * FROM documentsWHERE to_tsvector('simple', content) @@ to_tsquery('simple', 'keyword');
-- Stemmed search: a query for 'running' also matches 'runs'CREATE INDEX idx_content_stem ON documentsUSING gin(to_tsvector('english_stem', content));
SELECT * FROM documentsWHERE 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.
Ranking Results
Section titled “Ranking Results”SELECT content, ts_rank(to_tsvector('jieba', content), plainto_tsquery('jieba', '搜索词')) as rankFROM (VALUES ('全文搜索词法分析很重要'), ('数据库支持中文检索'), ('这段文字没有关键内容') ) AS d(content)WHERE to_tsvector('jieba', content) @@ plainto_tsquery('jieba', '搜索词')ORDER BY rank DESCLIMIT 10;Query Types
Section titled “Query Types”| Function | Description | Example |
|---|---|---|
plainto_tsquery | Simple phrase | plainto_tsquery('jieba', '人工智能') |
to_tsquery | Boolean operators | to_tsquery('simple', 'cat & dog') |
phraseto_tsquery | Exact phrase | phraseto_tsquery('simple', 'hello world') |
websearch_to_tsquery | Google-style | websearch_to_tsquery('simple', '"exact" -exclude') |
Boolean Search
Section titled “Boolean Search”-- AND: both terms must matchSELECT * FROM documentsWHERE tsv @@ to_tsquery('simple', 'database & performance');
-- OR: either term matchesSELECT * FROM documentsWHERE tsv @@ to_tsquery('simple', 'postgres | mysql');
-- NOT: exclude termSELECT * FROM documentsWHERE tsv @@ to_tsquery('simple', 'database & !oracle');
-- Prefix matchingSELECT * FROM documentsWHERE tsv @@ to_tsquery('simple', 'data:*');Highlight Search Results
Section titled “Highlight Search Results”SELECT ts_headline('jieba', content, plainto_tsquery('jieba', '数据库'), 'StartSel=<b>, StopSel=</b>, MaxWords=50' ) as highlightedFROM (VALUES ('数据库支持中文全文检索')) AS d(content)WHERE to_tsvector('jieba', content) @@ plainto_tsquery('jieba', '数据库');Search with Weights
Section titled “Search with Weights”-- Prioritize title matches over bodyALTER 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 rankingWITH q AS (SELECT plainto_tsquery('jieba', '搜索词') AS query)SELECT a.title, ts_rank(a.tsv, q.query) AS rankFROM articles a, qWHERE a.tsv @@ q.queryORDER BY rank DESC;Limits
Section titled “Limits”| Limit | Value |
|---|---|
Max tsvector value size | 1 MB |
Max lexemes per tsvector | ~264,000 |
| Supported text search configurations | 5 (jieba, chinese_ngram, simple, english, english_stem), plus the aliases chinese, zhparser, zhparser_ngram |
| GIN index build strategy | Sequential (full table scan) |
See Limits and Quotas for the complete list.
Next Steps
Section titled “Next Steps”- RAG with Built-in Embeddings — Combine FTS with vector search for hybrid retrieval
- Vector Search — Embedding and HNSW indexes for semantic search
- Extensions Overview — All 9 built-in extensions
- Limits and Quotas — All operational limits