pg_trgm
模块提供了基于三元组匹配确定字母数字文本相似性的函数和操作符,以及支持快速搜索相似字符串的索引操作符类。
此模块被认为是“受信任的”,也就是说,具有当前数据库的 CREATE
权限的非超级用户可以安装它。
三元组是从字符串中提取的三个连续字符的组合。我们可以通过计算它们共享的三元组的数量来衡量两个字符串的相似度。事实证明,这个简单的想法对于衡量许多自然语言中单词的相似度非常有效。
当从字符串中提取三元组时,pg_trgm
会忽略非单词字符(非字母数字)。在确定字符串中包含的三元组集合时,每个单词都被认为前缀有两个空格,后缀有一个空格。例如,字符串 “cat
” 中的三元组集合为 “ c
”、“ ca
”、“cat
” 和 “at
”。字符串 “foo|bar
” 中的三元组集合为 “ f
”、“ fo
”、“foo
”、“oo
”、“ b
”、“ ba
”、“bar
” 和 “ar
”。
pg_trgm
模块提供的函数如 表 F.25 所示,操作符如 表 F.26 所示。
表 F.25. pg_trgm
函数
考虑以下示例
# 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.26. pg_trgm
操作符
操作符 描述 |
---|
如果其参数的相似度大于 |
如果第一个参数中的三元组集合与第二个参数中连续的有序三元组集合之间的相似度大于 |
|
如果第二个参数的有序三元组集合存在一个连续的范围,与单词边界匹配,并且其与第一个参数的三元组集合的相似度大于由 |
|
返回参数之间的“距离”,即 1 减去 |
返回参数之间的“距离”,即 1 减去 |
|
返回参数之间的“距离”,即 1 减去 |
|
pg_trgm
模块提供了 GiST 和 GIN 索引操作符类,允许您在文本列上创建索引,以便进行非常快速的相似性搜索。这些索引类型支持上述相似性操作符,并且还支持基于三元组的索引搜索,用于 LIKE
、ILIKE
、~
、~*
和 =
查询。在 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 开始,这些索引类型还支持 LIKE
和 ILIKE
的索引搜索,例如
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 的相对性能特征,这些特征在其他地方讨论。
三元组匹配是一个非常有用的工具,当与全文索引结合使用时。特别是,它可以帮助识别拼写错误的输入单词,这些单词不会被全文搜索机制直接匹配。
第一步是生成一个辅助表,其中包含文档中的所有唯一单词
CREATE TABLE words AS SELECT word FROM ts_stat('SELECT to_tsvector(''simple'', bodytext) FROM documents');
其中 documents
是一个具有文本字段 bodytext
的表,我们希望搜索该表。使用 to_tsvector
函数的 simple
配置而不是使用特定于语言的配置的原因是,我们想要原始(未词干化)单词的列表。
接下来,在单词列上创建一个三元组索引
CREATE INDEX words_idx ON words USING GIN (word gin_trgm_ops);
现在,可以使用类似于先前示例的 SELECT
查询来建议用户搜索词中拼写错误的单词的拼写。一个有用的额外测试是要求所选单词的长度也与拼写错误的单词的长度相似。
由于 words
表是作为单独的静态表生成的,因此需要定期重新生成,以使其与文档集合保持合理最新的状态。通常不必使其完全最新。
GiST 开发站点 http://www.sai.msu.su/~megera/postgres/gist/
Tsearch2 开发站点 http://www.sai.msu.su/~megera/postgres/gist/tsearch/V2/
Oleg Bartunov <[email protected]>
, 莫斯科, 莫斯科大学, 俄罗斯
Teodor Sigaev <[email protected]>
, 莫斯科, Delta-Soft Ltd., 俄罗斯
Alexander Korotkov <[email protected]>
, 莫斯科, Postgres Professional, 俄罗斯
文档: Christopher Kings-Lynne
此模块由俄罗斯莫斯科的 Delta-Soft Ltd. 赞助。
如果您发现文档中的任何内容不正确、与您对特定功能的体验不符或需要进一步澄清,请使用此表单报告文档问题。