PostgreSQL

关注公众号 jb51net

关闭
首页 > 数据库 > PostgreSQL > PostgreSQL pg_trgm 模糊搜索

PostgreSQL pg_trgm 模糊搜索完全指南

作者:中年如酒

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);

选择建议:

二、插入测试数据

-- 插入产品(注意第二条有拼写错误 "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)

更适合匹配完整单词:

SELECT name, word_similarity('iPhone', name) as sim
FROM products
ORDER BY sim DESC;
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;

六、函数与操作符

主要函数

七、操作符速查表

操作符示例说明
%相似度匹配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);
CREATE INDEX trgm_gin_idx ON table_name USING gin (column_name gin_trgm_ops);

九、最佳实践

1.索引选择

2.阈值调整

3.性能优化

十、性能注意事项

十一、局限性

十二、总结

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

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

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

您可能感兴趣的文章:
阅读全文