PostgreSQL 全文搜索配置教程
PostgreSQL 内置了功能强大的全文搜索(Full Text Search)引擎,无需额外安装 Elasticsearch 等专用搜索引擎即可实现高质量的文本检索。对于中小型应用来说,PostgreSQL FTS 完全可以胜任搜索需求,同时减少了运维复杂度。本文将在搬瓦工 VPS 上详细讲解全文搜索的配置和使用,包括中文搜索支持。
一、全文搜索核心概念
- tsvector:文档的分词结果,存储词位(lexeme)及其位置信息。
- tsquery:搜索查询表达式,支持与(&)、或(|)、非(!)等逻辑运算。
- Text Search Configuration:分词配置,定义如何将文本拆分为词位。
-- 查看分词结果
SELECT to_tsvector('english', 'The quick brown fox jumps over the lazy dog');
-- 查看查询解析
SELECT to_tsquery('english', 'quick & fox');
-- 执行全文匹配
SELECT to_tsvector('english', 'The quick brown fox') @@ to_tsquery('english', 'quick & fox');
二、基础全文搜索实现
2.1 创建文章表
CREATE TABLE articles (
id SERIAL PRIMARY KEY,
title VARCHAR(500) NOT NULL,
body TEXT NOT NULL,
author VARCHAR(100),
published_at TIMESTAMP DEFAULT NOW(),
search_vector tsvector
);
-- 插入示例数据
INSERT INTO articles (title, body, author) VALUES
('Getting Started with PostgreSQL', 'PostgreSQL is a powerful open source relational database system with over 35 years of active development.', 'Zhang Wei'),
('PostgreSQL Performance Tuning', 'Learn how to optimize PostgreSQL queries and improve database performance through indexing and query optimization.', 'Li Ming'),
('Full Text Search in PostgreSQL', 'PostgreSQL provides a full text search engine that supports stemming, ranking, and highlighting of search results.', 'Wang Fang');
2.2 生成和维护搜索向量
-- 手动更新 search_vector
UPDATE articles SET search_vector =
setweight(to_tsvector('english', coalesce(title, '')), 'A') ||
setweight(to_tsvector('english', coalesce(body, '')), 'B');
-- 创建触发器自动维护 search_vector
CREATE FUNCTION articles_search_trigger() RETURNS trigger AS $$
BEGIN
NEW.search_vector :=
setweight(to_tsvector('english', coalesce(NEW.title, '')), 'A') ||
setweight(to_tsvector('english', coalesce(NEW.body, '')), 'B');
RETURN NEW;
END
$$ LANGUAGE plpgsql;
CREATE TRIGGER trig_articles_search
BEFORE INSERT OR UPDATE ON articles
FOR EACH ROW EXECUTE FUNCTION articles_search_trigger();
使用 setweight 可以为不同字段设置权重:A(最高)、B、C、D(最低)。标题中的匹配会比正文中的排名更高。
2.3 创建 GIN 索引
CREATE INDEX idx_articles_search ON articles USING GIN (search_vector);
2.4 执行搜索查询
-- 基础搜索
SELECT title, ts_rank(search_vector, query) AS rank
FROM articles, to_tsquery('english', 'postgresql & performance') AS query
WHERE search_vector @@ query
ORDER BY rank DESC;
-- 使用 websearch_to_tsquery(更友好的语法)
SELECT title, ts_rank(search_vector, query) AS rank
FROM articles, websearch_to_tsquery('english', 'postgresql performance') AS query
WHERE search_vector @@ query
ORDER BY rank DESC;
-- 前缀匹配
SELECT title FROM articles
WHERE search_vector @@ to_tsquery('english', 'optim:*');
三、搜索结果高亮显示
SELECT title,
ts_headline('english', body,
to_tsquery('english', 'postgresql & search'),
'StartSel=, StopSel=, MaxFragments=2, FragmentDelimiter= ... '
) AS highlighted_body
FROM articles
WHERE search_vector @@ to_tsquery('english', 'postgresql & search');
ts_headline 函数会在匹配的词周围添加标记(如 HTML 标签),非常适合在搜索结果页展示。
四、中文全文搜索配置
PostgreSQL 内置的分词器不支持中文。需要安装第三方中文分词扩展,推荐使用 zhparser 或 pg_jieba。
4.1 安装 zhparser
# 安装编译依赖
apt install postgresql-server-dev-16 build-essential -y
# 下载并编译 SCWS(Simple Chinese Word Segmentation)
cd /tmp
wget http://www.xunsearch.com/scws/down/scws-1.2.3.tar.bz2
tar xjf scws-1.2.3.tar.bz2
cd scws-1.2.3
./configure
make && make install
# 下载并编译 zhparser
cd /tmp
git clone https://github.com/amutu/zhparser.git
cd zhparser
make && make install
4.2 配置中文搜索
-- 创建扩展
CREATE EXTENSION zhparser;
-- 创建中文全文搜索配置
CREATE TEXT SEARCH CONFIGURATION chinese (PARSER = zhparser);
-- 添加词映射
ALTER TEXT SEARCH CONFIGURATION chinese ADD MAPPING FOR n,v,a,i,e,l WITH simple;
-- 测试中文分词
SELECT to_tsvector('chinese', '搬瓦工VPS是一款高性价比的虚拟专用服务器');
-- 中文搜索查询
SELECT to_tsquery('chinese', '搬瓦工 & 服务器');
4.3 中文搜索实践
-- 为中文内容创建搜索向量
ALTER TABLE articles ADD COLUMN search_vector_zh tsvector;
UPDATE articles SET search_vector_zh =
setweight(to_tsvector('chinese', coalesce(title, '')), 'A') ||
setweight(to_tsvector('chinese', coalesce(body, '')), 'B');
CREATE INDEX idx_articles_search_zh ON articles USING GIN (search_vector_zh);
五、高级搜索功能
5.1 短语搜索
-- 短语搜索(词语相邻)
SELECT title FROM articles
WHERE search_vector @@ phraseto_tsquery('english', 'full text search');
-- 指定词距
SELECT title FROM articles
WHERE search_vector @@ to_tsquery('english', 'full <2> search');
5.2 模糊搜索与拼写纠正
-- 安装 pg_trgm 扩展用于模糊匹配
CREATE EXTENSION pg_trgm;
-- 创建 trigram 索引
CREATE INDEX idx_articles_title_trgm ON articles USING GIN (title gin_trgm_ops);
-- 相似度搜索
SELECT title, similarity(title, 'postgrsql') AS sim
FROM articles
WHERE title % 'postgrsql'
ORDER BY sim DESC;
5.3 搜索建议(自动补全)
-- 基于前缀的搜索建议
SELECT DISTINCT title FROM articles
WHERE search_vector @@ to_tsquery('english', 'perf:*')
LIMIT 5;
六、搜索排名优化
-- ts_rank:基于词频的排名
SELECT title, ts_rank(search_vector, query) AS rank
FROM articles, to_tsquery('english', 'postgresql') AS query
WHERE search_vector @@ query
ORDER BY rank DESC;
-- ts_rank_cd:基于覆盖密度的排名(考虑词的接近程度)
SELECT title, ts_rank_cd(search_vector, query) AS rank
FROM articles, to_tsquery('english', 'postgresql') AS query
WHERE search_vector @@ query
ORDER BY rank DESC;
-- 自定义权重
SELECT title,
ts_rank(search_vector, query, 1) AS rank_log, -- 使用对数归一化
ts_rank(search_vector, query, 32) AS rank_div -- 除以文档长度
FROM articles, to_tsquery('english', 'postgresql') AS query
WHERE search_vector @@ query;
七、性能优化建议
- 预计算 tsvector:将分词结果存储在独立列中,避免查询时实时计算。
- GIN 索引:必须为 tsvector 列创建 GIN 索引,否则大表全文搜索会退化为全表扫描。
- 分区表:数据量超过千万级时考虑按时间或类别分区。
- 限制结果集:搜索查询务必加 LIMIT,避免返回过多结果。
- 监控索引大小:GIN 索引可能较大,定期执行
REINDEX维护。
八、何时需要专用搜索引擎
PostgreSQL FTS 适合大多数场景,但以下情况建议使用 Elasticsearch 或 Meilisearch:
- 需要分布式搜索(数据量超过数亿级)。
- 需要复杂的聚合分析和 faceted search。
- 需要极低延迟的即时搜索(as-you-type)。
- 多语言混合搜索的复杂需求。
总结
PostgreSQL 全文搜索是一个被低估的强大功能,对于中小型应用完全可以替代独立搜索引擎。通过合理的分词配置、权重设置和索引优化,可以在搬瓦工 VPS 上实现高质量的搜索体验。更多 PostgreSQL 教程可参考 JSON 数据查询 和 流复制配置。选购搬瓦工 VPS 请查看 全部方案,使用优惠码 NODESEEK2026 享受 6.77% 折扣,通过 bwh81.net 进入官网。