受支持版本: 当前版本 (18) / 17 / 16 / 15 / 14
开发版本: devel

F.32. pg_trgm #

pg_trgm模块提供函数和操作符,用于基于三元组匹配确定字母数字文本的相似度, 同时还提供支持快速搜索相似字符串的索引操作符类。

该模块被认为是受信任的,也就是说,它可以由在当前数据库上具有CREATE权限的非超级用户安装。

F.32.1. 三元组(Trigram 或 Trigraph)概念 #

三元组是一组从字符串中取出的三个连续字符。我们可以通过统计两个字符串共享的三元组数量来度量它们的相似度。 这个简单的思想在度量许多自然语言中词的相似度时都非常有效。

Note

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

F.32.2. 函数和操作符 #

pg_trgm模块提供的函数列在Table F.27中,操作符列在Table F.28中。

Table F.27. pg_trgm函数

函数

描述

similarity ( text, text ) → real

返回一个数值,表示两个参数的相似程度。 结果范围为 0 到 1:0 表示两个字符串完全不相似,1 表示两个字符串完全相同。

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更适合查找与词的一部分的相似度。

Table F.28. 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.32.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.32.4. 索引支持 #

pg_trgm模块提供 GiST 和 GIN 索引操作符类,允许你为文本列创建索引,以实现非常快速的相似度搜索。 这些索引类型支持前文所述的相似度操作符,并且还支持对LIKEILIKE~~*=查询执行基于三元组的索引搜索。 在默认构建的pg_trgm中,相似度比较不区分大小写。 不支持不等操作符。 注意,对于等值操作符,这些索引的效率可能不如常规 B-树索引。

示例:

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 操作符类将一组三元组近似表示为位图签名。 其可选整数参数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-树的搜索不同,搜索字符串不需要在左端锚定。

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

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

索引搜索的工作方式是从正则表达式中提取三元组,然后在索引中查找这些三元组。 能从正则表达式中提取出的三元组越多,索引搜索就越有效。 与基于 B-树的搜索不同,搜索字符串不需要在左端锚定。

对于LIKE和正则表达式搜索,都要记住:无法提取出三元组的模式会退化为全索引扫描。

GiST 和 GIN 索引之间如何取舍,取决于二者各自的相对性能特征;相关讨论见其他章节。

F.32.7. 作者 #

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

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

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

文档:Christopher Kings-Lynne

该模块由俄罗斯莫斯科的 Delta-Soft Ltd. 赞助。

提交更正

如果您发现文档中有不正确的内容、与您使用特定功能的经验不符或需要进一步说明,请使用此表单来报告文档问题。