-- Setup
DROPTABLEIFEXISTSdocs_fts;CREATETABLEdocs_fts(idbigintGENERATEDALWAYSASIDENTITYPRIMARYKEY,titletextNOTNULL,bodytextNOTNULL);INSERTINTOdocs_fts(title,body)VALUES('Postgres tips','PostgreSQL is a powerful relational database with full-text search built in.'),('SQL joins','Inner joins keep matching rows; left joins keep all left rows.'),('Indexing','B-tree indexes speed up equality and range queries. GIN indexes are great for arrays and text search.'),('Cats','Cats are not databases. This sentence exists to add noise.');-- to_tsvector parses, normalizes, and removes stop words
SELECTto_tsvector('english','PostgreSQL has powerful full-text search')ASv;-- to_tsquery turns a query string into a tsquery
SELECTto_tsquery('english','powerful & search')ASq;-- @@ tests "does this document match this query?"
SELECTtitleFROMdocs_ftsWHEREto_tsvector('english',title||' '||body)@@to_tsquery('english','powerful & search');-- websearch_to_tsquery: parses Google-style input (quotes, OR, -minus)
SELECTtitleFROMdocs_ftsWHEREto_tsvector('english',title||' '||body)@@websearch_to_tsquery('english','index OR join -cats');-- Add a generated tsvector column + GIN index for fast search at scale
ALTERTABLEdocs_ftsADDCOLUMNsearch_tsvtsvectorGENERATEDALWAYSAS(to_tsvector('english',title||' '||body))STORED;CREATEINDEXdocs_fts_search_idxONdocs_ftsUSINGgin(search_tsv);-- Rank results
SELECTtitle,ts_rank(search_tsv,websearch_to_tsquery('english','database search'))ASrankFROMdocs_ftsWHEREsearch_tsv@@websearch_to_tsquery('english','database search')ORDERBYrankDESC;DROPTABLEIFEXISTSdocs_fts;