Full-Text Search with tsvector and tsquery
Advanced18 min
Build a powerful full-text search engine using PostgreSQL native tsvector columns, GIN indexes, and ranked query results.
Prerequisites
- -PostgreSQL 14+
- -A table with text content to search
Steps
1
Add a tsvector column to your table
Create a generated tsvector column that automatically stays in sync with the source text.
$ psql -U postgres -d mydb -c "ALTER TABLE articles ADD COLUMN search_vector tsvector GENERATED ALWAYS AS (to_tsvector('english', coalesce(title, '') || ' ' || coalesce(body, ''))) STORED;"
GENERATED ALWAYS AS creates a stored computed column that updates automatically when title or body change.
2
Create a GIN index for fast search
Add a GIN index on the tsvector column for efficient full-text queries.
$ psql -U postgres -d mydb -c "CREATE INDEX idx_articles_search ON articles USING GIN (search_vector);"
3
Run a basic full-text search
Search for articles matching a text query with automatic stemming.
$ psql -U postgres -d mydb -c "SELECT id, title, ts_rank(search_vector, to_tsquery('english', 'database & performance')) AS rank FROM articles WHERE search_vector @@ to_tsquery('english', 'database & performance') ORDER BY rank DESC LIMIT 10;"
4
Use websearch_to_tsquery for user-friendly input
Convert natural language search input into a tsquery without manual operators.
$ psql -U postgres -d mydb -c "SELECT id, title FROM articles WHERE search_vector @@ websearch_to_tsquery('english', 'how to optimize database queries') ORDER BY ts_rank(search_vector, websearch_to_tsquery('english', 'how to optimize database queries')) DESC LIMIT 10;"
websearch_to_tsquery handles quoted phrases, OR, and - (NOT) operators like a web search engine.
5
Generate search result snippets
Highlight matching terms in search results with ts_headline.
$ psql -U postgres -d mydb -c "SELECT id, title, ts_headline('english', body, to_tsquery('english', 'performance'), 'StartSel=<b>, StopSel=</b>, MaxWords=35, MinWords=15') AS snippet FROM articles WHERE search_vector @@ to_tsquery('english', 'performance') LIMIT 5;"
Full Script
FAQ
Discussion
Loading comments...