Redrock Postgres 搜索 英文
版本: 9.3 / 9.4 / 9.5 / 9.6 / 10 / 11 / 12 / 13 / 14 / 15 / 16 / 17

F.33. pg_trgm — 利用三元组匹配支持文本相似性 #

F.33.1. 三元组(或三字组)概念
F.33.2. 函数和运算符
F.33.3. GUC 参数
F.33.4. 索引支持
F.33.5. 文本搜索集成
F.33.6. 引用
F.33.7. 作者

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

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

F.33.1. 三元组(或三字组)概念 #

三元组是从字符串获取的连续三个字符的组。我们可以通过计算其共享的三元组数量来衡量两个字符串的相似性。这个简单的想法被证明对衡量许多自然语言单词的相似性非常有效。

注意

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

F.33.2. 函数和运算符 #

pg_trgm 模块提供的函数显示在 表格 F.25 中,运算符显示在 表格 F.26 中。

表格 F.25. pg_trgm 函数

函数

说明

similarity ( text, text ) → real

返回一个数字,它表示两个参数的相似程度。结果范围为零(表示两个字符串完全不相似)到一(表示两个字符串相同)。

show_trgm ( text ) → text[]

返回给定字符串中所有三元组的数组。(实际上,这通常没用,除了用于调试。)

word_similarity ( text, text ) → real

返回一个数字,表示第一个字符串中的三元组集合与第二个字符串中连续有序三元组集合之间的最大相似度。有关详细信息,请参阅以下说明。

strict_word_similarity ( text, text ) → real

word_similarity 相同,但强制范围边界与单词边界匹配。由于我们没有跨单词三元组,此函数实际上会返单词 string 和第二个 string 中任何连续单词范围之间的最大相似度。

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)

在第一个 string 中,三元组的集合是 {" w"," wo","wor","ord","rd "}。在第二个 string 中,有序的三元组集合是 {" t"," tw","two","wo "," w"," wo","wor","ord","rds","ds "}。第二个 string 中最相似的有序三元组范围为 {" w"," wo","wor","ord"},而相似度为 0.8

此函数返回一个值,该值可近似理解为第一个 string 和第二个 string 中的任何子串之间的最大相似度。但是,此函数不会在范围的边界处添加填充。因此,第二个 string 中存在的其他字符数不会被考虑,除了不匹配的单词边界外。

同时,strict_word_similarity 会在第二个 string 中选择一个单词范围。在上述示例中,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.26. 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

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

text <<-> textreal

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

text <->> textreal

<<-> 运算符的换向器。

text <<<-> textreal

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

text <->>> textreal

<<<-> 运算符的换向器。


F.33.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.33.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 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 树的搜索不同,搜索字符串不必左锚定。

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

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

索引搜索通过从正则表达式中提取三元组,然后在索引中查找三元组来工作。从正则表达式中提取的三元组越多,索引搜索就越有效。与基于 B 树的搜索不同,搜索字符串不必左锚定。

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

在 GiST 和 GIN 索引之间进行选择取决于 GiST 和 GIN 的相对性能特征,这些特征在其他地方进行了讨论。

F.33.6 参考资料 #

GiST 开发网站 http://www.sai.msu.su/~megera/postgres/gist/

Tsearch2 开发网站 http://www.sai.msu.su/~megera/postgres/gist/tsearch/V2/

F.33.7 作者 #

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

Teodor Sigaev ,莫斯科,俄罗斯,Delta-Soft 公司

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

文档:Christopher Kings-Lynne

此模块由俄罗斯莫斯科 Delta-Soft 有限公司赞助。