PostgreSQL pg_trgm 模糊搜索完全指南

 更新时间:2025年11月12日 10:18:48   作者:中年如酒  
PostgreSQL的pg_trgm扩展通过三字符组合实现模糊文本搜索,支持处理拼写错误和部分匹配,下面就来详细的介绍一下PostgreSQL pg_trgm 模糊搜索完全指南,感兴趣的可以了解一下

什么是 pg_trgm?

pg_trgm 是 PostgreSQL 的一个扩展模块,用于实现基于三元组(trigram)的模糊文本搜索。它可以帮你找到拼写错误、部分匹配的文本,非常适合搜索功能。

三元组(Trigram)原理

三元组是将文本分解为连续的三个字符的组合:

SELECT show_trgm('iPhone');
-- 结果: {"  i"," ip","hon","iph","ne ","one","pho"}

通过比较两个字符串的三元组重叠度,可以计算相似度。

一、环境准备

1. 创建扩展

CREATE EXTENSION IF NOT EXISTS pg_trgm;

2. 创建测试表

CREATE TABLE products (
  tenant_id uuid,
  id integer,
  name text,
  description text,
  PRIMARY KEY (tenant_id, id)
);

3. 创建索引(性能关键)

有两种索引类型可选:

-- GiST 索引:平衡型,更新快,占用空间小
CREATE INDEX trgm_idx_products_name 
ON products USING gist (name gist_trgm_ops);

-- GIN 索引:查询更快,但更新慢,占用更多空间
CREATE INDEX trgm_gin_idx_products_name 
ON products USING gin (name gin_trgm_ops);

选择建议:

  • 读多写少 → 用 GIN
  • 频繁更新 → 用 GiST

二、插入测试数据

-- 插入产品(注意第二条有拼写错误 "iPhne")
INSERT INTO products (tenant_id, id, name, description) VALUES
  ('d1c06023-3421-4fbb-9dd1-c96e42d2fd02', 1, 'iPhone 13 Pro', 'Latest Apple smartphone'),
  ('d1c06023-3421-4fbb-9dd1-c96e42d2fd02', 2, 'iPhne 13', 'Budget Apple smartphone'),
  ('d1c06023-3421-4fbb-9dd1-c96e42d2fd02', 3, 'Samsung Galaxy S21', 'Android flagship phone');

三、核心查询方法

1. 计算相似度

-- 返回 0 到 1 之间的数字(1 = 完全相同)
SELECT similarity('iPhone', 'iPhne');
-- 结果: 0.5454545

2. 整体相似度匹配(% 操作符)

-- 查找与 'iPhone' 相似的产品名
SELECT name, similarity(name, 'iPhone') AS sim
FROM products
WHERE name % 'iPhone'  -- 相似度超过阈值
ORDER BY sim DESC;

输出结果:

     name      |    sim
---------------+------------
 iPhone 13 Pro |        0.5
 iPhne 13      | 0.33333334
(2 rows)

3. 子串相似度匹配(%> 操作符)

适合搜索包含某个词的文本:

-- 查找包含 'phone' 的产品
SELECT name, similarity(name, 'phone') AS sim
FROM products
WHERE name %> 'phone'
ORDER BY sim DESC;

输出:

     name      |    sim
---------------+------------
 iPhone 13 Pro | 0.33333334
(1 row)

四、高级功能

1. 调整相似度阈值

默认阈值是 0.3,可以调整

SET pg_trgm.similarity_threshold = 0.5;

再次查询,只返回相似度 ≥ 0.5 的结果

SELECT name
FROM products
WHERE name % 'iPhone';

2. 单词相似度(Word Similarity)

更适合匹配完整单词:

  • word_similarity: 从左到右查找最相似的词
SELECT name, word_similarity('iPhone', name) as sim
FROM products
ORDER BY sim DESC;
  • strict_word_similarity: 更严格的单词边界匹配
SELECT name, strict_word_similarity('iPhone', name) as sim
FROM products
ORDER BY sim DESC;

五、实战场景

场景 1:容错搜索(处理拼写错误)

方法 1:降低相似度阈值

  • 先查看相似度
SELECT similarity('iPhone 13 Pro', 'ipone');  -- 结果约 0.25
  • 临时降低阈值(针对单次查询)
BEGIN;
SET LOCAL pg_trgm.similarity_threshold = 0.2;

SELECT name, similarity(name, 'ipone') AS score
FROM products
WHERE tenant_id = 'd1c06023-3421-4fbb-9dd1-c96e42d2fd02'
  AND name % 'ipone'
ORDER BY score DESC
LIMIT 5;

COMMIT;  -- 或 ROLLBACK,阈值会自动恢复

输出:

     name      | score
---------------+-------
 iPhone 13 Pro |  0.25
 iPhne 13      |  0.25
(2 rows)

方法 2:不用 % 操作符(推荐)

直接用 similarity() 函数,手动过滤:

SELECT name, similarity(name, 'ipone') AS score
FROM products
WHERE tenant_id = 'd1c06023-3421-4fbb-9dd1-c96e42d2fd02'
  AND similarity(name, 'ipone') > 0.15  -- 自定义阈值
ORDER BY score DESC
LIMIT 5;

注意:方法 2 性能较差(无法用索引),适合小数据集。对于大表,使用方法 1 配合索引。

场景 2:自动补全(更好的解决方案)

用户输入 “iPh”,显示候选项。使用 word_similarity 更适合前缀匹配:

SELECT name, word_similarity('iPh', name) AS score
FROM products
WHERE tenant_id = 'd1c06023-3421-4fbb-9dd1-c96e42d2fd02'
  AND 'iPh' <% name  -- word_similarity 操作符
ORDER BY score DESC
LIMIT 10;

或使用 LIKE(性能更好):

SELECT name
FROM products
WHERE tenant_id = 'd1c06023-3421-4fbb-9dd1-c96e42d2fd02'
  AND name ILIKE 'iPh%'  -- 大小写不敏感
ORDER BY name
LIMIT 10;

场景 3:去重(找到相似的重复数据)

SELECT p1.name, p2.name, similarity(p1.name, p2.name) AS sim
FROM products p1
JOIN products p2 ON p1.id < p2.id
WHERE p1.tenant_id = p2.tenant_id
  AND p1.name % p2.name
  AND similarity(p1.name, p2.name) > 0.7
ORDER BY sim DESC;

六、函数与操作符

主要函数

  • similarity (text, text):返回两个字符串的相似度(0 至 1 之间)
  • show_trgm (text):显示字符串中的三元组
  • word_similarity (text, text):返回基于单词的相似度
  • strict_word_similarity (text, text):返回严格基于单词的相似度
  • show_limit ():显示当前的相似度阈值

七、操作符速查表

操作符示例说明
%相似度匹配name % ‘iPhone’
%>子串相似度(左边在右边中)‘phone’ %> name
< %子串相似度(右边在左边中)name <% ‘phone’
similarity()计算相似度分数similarity(name, ‘iPhone’)
word_similarity()单词相似度word_similarity(‘iPhone’, name)

大小写敏感性:默认区分大小写,可以用 LOWER() 转换

WHERE LOWER(name) % LOWER('iphone')

八、索引类型

pg_trgm 支持两种索引类型:

GiST:

CREATE INDEX trgm_gist_idx ON table_name USING gist (column_name gist_trgm_ops);
  • 搜索与更新的性能平衡
  • 更小的索引体积
  • 适用于动态数据
  • GIN索引:
CREATE INDEX trgm_gin_idx ON table_name USING gin (column_name gin_trgm_ops);

  • 搜索速度更快
  • 更新速度较慢
  • 索引体积更大
  • 更适用于静态数据

九、最佳实践

1.索引选择

  • 以读取操作为主的数据,使用 GIN 索引
  • 频繁更新的数据,使用 GiST 索引
  • 仅为频繁搜索的列创建索引

2.阈值调整

  • 较低阈值(如 0.2)可获得更多匹配结果
  • 较高阈值(如 0.5)可实现更严格的匹配
  • 结合自身数据测试,找到最优值

3.性能优化

  • 全词匹配场景使用 word_similarity () 函数
  • 仅对特定列创建索引,而非所有文本列
  • 监控索引体积,必要时重建索引

十、性能注意事项

  • GIN 索引搜索速度更快,但更新速度较慢
  • 包含大量唯一值的文本列,索引体积可能较大
  • 大型表可考虑使用部分索引
  • 根据误报 / 漏报率,监控并调整相似度阈值

十一、局限性

  • 不适用于极短字符串(少于 3 个字符)
  • 可能产生误报结果
  • 大型文本列的索引体积可能较大
  • 不适合精确匹配(建议使用标准索引)

十二、总结

pg_trgm 是实现模糊搜索的强大工具,适用于:

  • 模糊搜索功能
  • 拼写检查建议
  • 自动补全功能
  • 查找相似产品名称
  • 匹配含拼写错误的地址
  • 容忍拼写错误的搜索

关键是创建合适的索引和调整相似度阈值,就能在保证性能的前提下提供出色的用户体验。

到此这篇关于PostgreSQL pg_trgm 模糊搜索完全指南的文章就介绍到这了,更多相关PostgreSQL pg_trgm 模糊搜索内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • PostgreSQL中实现自增的三种方式举例

    PostgreSQL中实现自增的三种方式举例

    很多小伙伴在把mysql数据库里面的表导入pgsql数据库的时候,会遇到新增数据的时候id不自增,这篇文章主要给大家介绍了关于PostgreSQL中实现自增的三种方式,需要的朋友可以参考下
    2024-02-02
  • 基于PostgreSql 别名区分大小写的问题

    基于PostgreSql 别名区分大小写的问题

    这篇文章主要介绍了基于PostgreSql 别名区分大小写的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-01-01
  • PostgreSQL12同步流复制搭建及主备切换方式

    PostgreSQL12同步流复制搭建及主备切换方式

    这篇文章主要介绍了PostgreSQL12同步流复制搭建及主备切换方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-03-03
  • PostgreSQL数据库中窗口函数的语法与使用

    PostgreSQL数据库中窗口函数的语法与使用

    这PostgreSQL中提供了窗口函数,一个窗口函数在一系列与当前行有某种关联的表行上进行一种计算。下面这篇文章主要给大家介绍了关于PostgreSQL数据库中窗口函数的语法与使用的相关资料,需要的朋友可以参考下
    2019-03-03
  • PostgreSQL auto_explain的具体使用

    PostgreSQL auto_explain的具体使用

    PostgreSQL auto_explain插件自动记录慢SQL执行计划,支持全局、会话及用户级别加载,具有一定的参考价值,感兴趣的可以了解一下
    2025-06-06
  • 免密使用PostgreSQL数据库内置工具的两种方法

    免密使用PostgreSQL数据库内置工具的两种方法

    我们在PostgreSQL数据库自带的各种工具时,每次使用都要输入数据库密码,这里我们通过配置的方式,以后再使用这些工具就不需要输入数据库密码了,需要的朋友可以参考下
    2025-03-03
  • PostgreSQL进行重置密码的方法小结

    PostgreSQL进行重置密码的方法小结

    今天想测试一个PostgresSQL语法的 SQL,但是打开PostgresSQL之后沉默了,密码是什么?日长月久的,渐渐就忘记了,于是开始了寻找密码的道路,所以本文介绍了Postgresql忘记密码,如何重置密码,需要的朋友可以参考下
    2024-05-05
  • windows PostgreSQL 9.1 安装详细步骤

    windows PostgreSQL 9.1 安装详细步骤

    这篇文章主要介绍了windows PostgreSQL 9.1 安装详细步骤,需要的朋友可以参考下
    2016-11-11
  • Postgresql 通过出生日期获取年龄的操作

    Postgresql 通过出生日期获取年龄的操作

    这篇文章主要介绍了Postgresql 通过出生日期获取年龄的操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-12-12
  • PostgreSQL定时清理旧数据的实现方法

    PostgreSQL定时清理旧数据的实现方法

    最近觉得数据库中每日数据不需要都保持,只需要保留30天的,所以这篇文章给大家介绍了PostgreSQL定时清理旧数据的实现方法,文中通过代码示例和图文给大家介绍的非常详细,具有一定的参考价值,需要的朋友可以参考下
    2024-03-03

最新评论