2025年9月25日: PostgreSQL 18 发布!
支持版本: 当前 (18) / 17 / 16 / 15 / 14 / 13
开发版本: devel
不支持的版本: 12 / 11 / 10 / 9.6 / 9.5 / 9.4 / 9.3 / 9.2 / 9.1 / 9.0 / 8.4 / 8.3

F.35. pg_trgm — 使用三字母组匹配进行文本相似度支持 #

pg_trgm 模块提供函数和运算符,用于基于三字母组匹配来确定字母数字文本的相似度,以及支持快速查找相似字符串的索引操作符类。

此模块被认为是受信任的,这意味着非超级用户也可以在其拥有的数据库上安装它,前提是他们具有 CREATE 权限。

F.35.1. 三字母组(或 Trigraph)概念 #

三字母组是从字符串中取出的三个连续字符组成的组。我们可以通过计算两个字符串共享的三字母组的数量来衡量它们的相似度。这个简单的想法被证明在衡量许多自然语言单词的相似度方面非常有效。

注意

pg_trgm 在从字符串提取三字母组时会忽略非单词字符(非字母数字字符)。在确定字符串所包含的三字母组集合时,每个单词被认为前面有两个空格,后面有一个空格。例如,字符串 cat 的三字母组集合是 ccacatat。字符串 foo|bar 的三字母组集合是 ffofoooobbabarar

F.35.2. 函数和运算符 #

pg_trgm 模块提供的函数在 表 F.26 中列出,运算符在 表 F.27 中列出。

表 F.26. pg_trgm 函数

函数

描述

similarity ( text, text ) → real

返回一个指示两个参数有多相似的数字。结果的范围是从零(表示两个字符串完全不相似)到一(表示两个字符串相同)。

show_trgm ( text ) → text[]

返回给定字符串中所有三字母组的数组。(实际上这很少有用,除非用于调试。)

word_similarity ( text, text ) → real

返回一个数字,指示第一个字符串中的三字母组集合与第二个字符串中任何连续有序三字母组集合的匹配度。详情请参阅下文解释。

strict_word_similarity ( text, text ) → real

word_similarity 相同,但强制匹配词语边界。由于我们没有跨词语的三字母组,此函数实际上返回第一个字符串与第二个字符串中任何连续词语集合之间的最大相似度。

show_limit () → real

返回由 % 运算符使用的当前相似度阈值。这设置了两个单词之间被认为是拼写错误的最小相似度。(已弃用;改用 SHOW pg_trgm.similarity_threshold。)

set_limit ( real ) → real

设置由 % 运算符使用的当前相似度阈值。阈值必须在 0 和 1 之间(默认值为 0.3)。返回传递的值。(已弃用;改用 SET pg_trgm.similarity_threshold。)


请考虑以下示例

# SELECT word_similarity('word', 'two words');
 word_similarity
-----------------
             0.8
(1 row)

在第一个字符串中,三字母组集合是 {" w"," wo","wor","ord","rd "}。在第二个字符串中,有序三字母组集合是 {" t"," tw","two","wo "," w"," wo","wor","ord","rds","ds "}。第二个字符串中最相似的有序三字母组集合是 {" w"," wo","wor","ord"},相似度为 0.8

此函数返回的值可以大致理解为第一个字符串与第二个字符串的任何子串之间的最大相似度。但是,此函数不会为匹配范围的边界添加填充。因此,第二个字符串中存在的额外字符数量不会被考虑,除了不匹配的词语边界。

同时,strict_word_similarity 会选择第二个字符串中的一个词语范围。在上面的示例中,strict_word_similarity 会选择单个词语 'words' 的范围,其三字母组集合为 {" w"," wo","wor","ord","rds","ds "}

# SELECT strict_word_similarity('word', 'two words'), similarity('word', 'words');
 strict_word_similarity | similarity
------------------------+------------
               0.571429 |   0.571429
(1 row)

因此,strict_word_similarity 函数对于查找整个词语的相似度很有用,而 word_similarity 则更适合查找词语部分的相似度。

表 F.27. pg_trgm 运算符

运算符

描述

text % textboolean

如果其参数的相似度大于由 pg_trgm.similarity_threshold 设置的当前相似度阈值,则返回 true

text <% textboolean

如果第一个参数中的三字母组集合与第二个参数中的连续有序三字母组集合的相似度大于由 pg_trgm.word_similarity_threshold 参数设置的当前词语相似度阈值,则返回 true

text %> textboolean

<% 运算符的交换律。

text <<% textboolean

如果其第二个参数具有匹配词语边界的连续有序三字母组集合,并且其与第一个参数的三字母组集合的相似度大于由 pg_trgm.strict_word_similarity_threshold 参数设置的当前严格词语相似度阈值,则返回 true

text %>> textboolean

<<% 运算符的交换律。

text <-> textreal

返回参数之间的“距离”,即 1 减去 similarity() 值。

text <<-> textreal

返回参数之间的“距离”,即 1 减去 word_similarity() 值。

text <->> textreal

<<-> 运算符的交换律。

text <<<-> textreal

返回参数之间的“距离”,即 1 减去 strict_word_similarity() 值。

text <->>> textreal

<<<-> 运算符的交换律。


F.35.3. GUC 参数 #

pg_trgm.similarity_threshold (real) #

设置由 % 运算符使用的当前相似度阈值。阈值必须在 0 和 1 之间(默认值为 0.3)。

pg_trgm.word_similarity_threshold (real) #

设置由 <%%> 运算符使用的当前词语相似度阈值。阈值必须在 0 和 1 之间(默认值为 0.6)。

pg_trgm.strict_word_similarity_threshold (real) #

设置由 <<%%>> 运算符使用的当前严格词语相似度阈值。阈值必须在 0 和 1 之间(默认值为 0.5)。

F.35.4. 索引支持 #

pg_trgm 模块提供 GiST 和 GIN 索引操作符类,允许您在文本列上创建索引,以实现非常快速的相似度搜索。这些索引类型支持上述相似度运算符,并且还支持基于三字母组的 LIKEILIKE~~*= 查询的索引搜索。在 pg_trgm 的默认构建中,相似度比较是不区分大小写的。不支持不等价运算符。请注意,对于相等运算符,这些索引可能不如常规 B-tree 索引高效。

示例:

CREATE TABLE test_trgm (t text);
CREATE INDEX trgm_idx ON test_trgm USING GIST (t gist_trgm_ops);

CREATE INDEX trgm_idx ON test_trgm USING GIN (t gin_trgm_ops);

gist_trgm_ops GiST opclass 使用位图签名来近似三字母组集合。其可选的整数参数 siglen 决定了签名的长度(以字节为单位)。默认长度为 12 字节。有效的签名长度值为 1 到 2024 字节之间。更长的签名会导致更精确的搜索(扫描索引的一部分和更少的堆页面),但会增加索引的大小。

使用 32 字节签名长度创建此类索引的示例

CREATE INDEX trgm_idx ON test_trgm USING GIST (t gist_trgm_ops(siglen=32));

此时,您将在 t 列上有一个索引,可用于相似度搜索。典型的查询是

SELECT t, similarity(t, 'word') AS sml
  FROM test_trgm
  WHERE t % 'word'
  ORDER BY sml DESC, t;

这将返回文本列中与 word 足够相似的所有值,并按最佳匹配到最差的顺序排序。即使在非常大的数据集上,索引也将被用来使此操作快速执行。

上面查询的一个变体是

SELECT t, t <-> 'word' AS dist
  FROM test_trgm
  ORDER BY dist LIMIT 10;

GiST 索引可以非常有效地实现这一点,但 GIN 索引不能。当只需要最接近的匹配项时,它通常会比第一种方法效果更好。

您还可以使用 t 列上的索引来进行词语相似度或严格词语相似度搜索。典型的查询是

SELECT t, word_similarity('word', t) AS sml
  FROM test_trgm
  WHERE 'word' <% t
  ORDER BY sml DESC, t;

SELECT t, strict_word_similarity('word', t) AS sml
  FROM test_trgm
  WHERE 'word' <<% t
  ORDER BY sml DESC, t;

这将返回文本列中所有其对应的有序三字母组集合的连续部分与 word 的三字母组集合足够相似的值,并按最佳匹配到最差的顺序排序。即使在非常大的数据集上,索引也将被用来使此操作快速执行。

上面查询的可能变体是

SELECT t, 'word' <<-> t AS dist
  FROM test_trgm
  ORDER BY dist LIMIT 10;

SELECT t, 'word' <<<-> t AS dist
  FROM test_trgm
  ORDER BY dist LIMIT 10;

GiST 索引可以非常有效地实现这一点,但 GIN 索引不能。

PostgreSQL 9.1 开始,这些索引类型还支持 LIKEILIKE 的索引搜索,例如

SELECT * FROM test_trgm WHERE t LIKE '%foo%bar';

索引搜索通过从搜索字符串中提取三字母组,然后在索引中查找它们来实现。搜索字符串中的三字母组越多,索引搜索就越有效。与 B-tree 搜索不同,搜索字符串不必是左锚定的。

PostgreSQL 9.3 开始,这些索引类型还支持正则表达式匹配(~~* 运算符)的索引搜索,例如

SELECT * FROM test_trgm WHERE t ~ '(foo|bar)';

索引搜索通过从正则表达式中提取三字母组,然后在索引中查找它们来实现。从正则表达式中提取的三字母组越多,索引搜索就越有效。与 B-tree 搜索不同,搜索字符串不必是左锚定的。

对于 LIKE 和正则表达式搜索,请记住,没有可提取三字母组的模式将退化为完全索引扫描。

GiST 和 GIN 索引之间的选择取决于 GiST 和 GIN 的相对性能特征,这些在别处有讨论。

F.35.7. 作者 #

Oleg Bartunov ,莫斯科,莫斯科大学,俄罗斯

Teodor Sigaev ,莫斯科,Delta-Soft Ltd.,俄罗斯

Alexander Korotkov ,莫斯科,Postgres Professional,俄罗斯

文档:Christopher Kings-Lynne

本模块由 Delta-Soft Ltd.(俄罗斯莫斯科)赞助。

提交更正

如果您在文档中发现任何不正确、与您在该特定功能上的经验不符或需要进一步澄清的内容,请使用 此表单 报告文档问题。