← 返回题目列表

PostgreSQL 全文检索是怎么做的?tsvector 和 GIN 索引有什么作用?

高频 中等 第 8 / 31 题 更新于 2026/07/29
PostgreSQL全文检索tsvectorGIN

简化版

PostgreSQL 全文检索会把文本转换成 tsvector,查询词转换成 tsquery,再用匹配运算符检索。GIN 索引能加速词项倒排查询。它适合中小规模站内搜索和简单相关性排序,但复杂中文分词、海量搜索和高级召回通常要考虑 Elasticsearch 等搜索引擎。

详细版

核心概念:

  • tsvector:文本分词、归一化后的词项集合。
  • tsquery:查询条件,可表达 AND、OR、NOT。
  • GIN 索引:适合加速词项包含关系。
  • ts_rank:用于相关性排序。

示例:

select *
from article
where search_vector @@ plainto_tsquery('english', 'postgres index');

PostgreSQL 全文检索适合和事务数据放在一起的轻量搜索,但中文分词和复杂搜索体验要额外评估。

完整版教学

一、全文检索不是简单 like

like '%keyword%' 是字符串匹配,通常难以利用普通 B-tree 索引,且不能理解词形变化、相关性和组合查询。全文检索会先把文本变成词项,再按词项检索。

例如英文里 runningrunsrun 可以归一化到相近词根。查询不再只是字符包含,而是词项匹配。

原文: PostgreSQL indexes improve searching
tsvector: 'index':2 'improv':3 'postgresql':1 'search':4

记忆钩子:全文检索查的是“词项”,不是单纯查一段字符串。

二、tsvector 保存可检索词项

tsvector 是 PostgreSQL 全文检索的核心数据结构。它保存从文本中提取出来的词项和位置。

select to_tsvector('english', 'PostgreSQL indexes improve searching');

结果会包含归一化后的词项。实际表中可以用生成列或触发器维护 search_vector 字段,避免每次查询都临时转换。

如果每次查询都对正文调用 to_tsvector,大表会很慢。预先存好并建索引才是常见工程做法。

三、tsquery 表达查询条件

查询词会被转换成 tsquery。简单输入可以用 plainto_tsquery,它会把普通文本转成查询表达式。

select *
from article
where search_vector @@ plainto_tsquery('english', 'postgres index');

@@ 表示全文匹配。复杂查询还可以表达 AND、OR、NOT,例如 postgres & index

用户搜索框通常不要直接拼接 tsquery 字符串,而应使用安全函数转换,避免语法错误和注入风险。

四、GIN 索引用来加速倒排查询

全文检索本质上需要从词项找到包含它的文档,这和倒排索引思路一致。PostgreSQL 常用 GIN 索引加速 tsvector 查询。

create index idx_article_search
on article using gin(search_vector);

没有 GIN 索引时,查询可能要扫描大量行并计算匹配;有索引后,可以快速定位包含词项的行。

GIN 索引写入和维护成本比普通 B-tree 高,所以适合读多搜索场景,写入极高的表要评估。

五、相关性排序可以用 ts_rank

搜索结果不只要匹配,还要排序。PostgreSQL 提供 ts_rank 等函数计算相关性。

select title,
       ts_rank(search_vector, plainto_tsquery('english', 'postgres index')) as rank
from article
where search_vector @@ plainto_tsquery('english', 'postgres index')
order by rank desc
limit 20;

相关性排序会增加计算成本。大结果集排序时要结合过滤条件、limit 和索引策略,不能无脑全量算 rank。

六、中文搜索要特别评估分词

PostgreSQL 内置全文检索对英文等语言支持较成熟,但中文没有天然空格分词,效果取决于配置和扩展。简单中文站内搜索可以用 trigram 或扩展方案,复杂搜索通常交给专业搜索引擎。

需求可选方案
英文文档搜索PostgreSQL FTS
简单模糊匹配pg_trgm
复杂中文分词搜索扩展或 Elasticsearch
海量搜索与召回专业搜索引擎

面试时要说明 PostgreSQL 能做全文检索,但不是 Elasticsearch 的完全替代品。

七、常见误区与追问

  • 误区:全文检索就是 like。 全文检索基于词项、词典、查询表达式和倒排索引。
  • 误区:建了 GIN 索引就没有成本。 GIN 写入和维护更重,要评估读写比例。
  • 误区:PostgreSQL 全文检索能完全替代 ES。 复杂中文分词、海量召回和搜索运营能力仍适合专业搜索引擎。
  • 追问:tsvector 和 tsquery 区别? 前者是文档词项,后者是查询表达式。
  • 追问:为什么用 GIN? GIN 适合一个值包含多个词项的倒排检索。
  • 追问:如何做相关性排序? 使用 ts_rank,但要注意大结果集排序成本。

八、面试中可以这样落地

文章搜索可以增加 search_vector 字段,写入或更新文章时维护它,并建 GIN 索引。

alter table article add column search_vector tsvector;
create index idx_article_search on article using gin(search_vector);

如果中文搜索要求高,就说明 PostgreSQL 可做轻量站内搜索,复杂召回、分词、同义词、拼写纠错应考虑 Elasticsearch 或 OpenSearch。

九、加强记忆

PostgreSQL 全文检索记住四个词:tsvector 存文档词项,tsquery 表达查询,@@ 做匹配,GIN 做加速。它适合轻量搜索和事务数据贴近场景,但中文复杂搜索和海量召回要评估专业搜索引擎。