pg_trgm
模块提供函数和运算符,用于基于三字母组匹配来确定字母数字文本的相似度,以及支持快速查找相似字符串的索引操作符类。
此模块被认为是“受信任的”,这意味着非超级用户也可以在其拥有的数据库上安装它,前提是他们具有 CREATE
权限。
三字母组是从字符串中取出的三个连续字符组成的组。我们可以通过计算两个字符串共享的三字母组的数量来衡量它们的相似度。这个简单的想法被证明在衡量许多自然语言单词的相似度方面非常有效。
pg_trgm
在从字符串提取三字母组时会忽略非单词字符(非字母数字字符)。在确定字符串所包含的三字母组集合时,每个单词被认为前面有两个空格,后面有一个空格。例如,字符串 “cat
” 的三字母组集合是 “ c
”、“ ca
”、“cat
” 和 “at
”。字符串 “foo|bar
” 的三字母组集合是 “ f
”、“ fo
”、“foo
”、“oo
”、“ b
”、“ ba
”、“bar
” 和 “ar
”。
由 pg_trgm
模块提供的函数在 表 F.26 中列出,运算符在 表 F.27 中列出。
表 F.26. 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.27. pg_trgm
运算符
运算符 描述 |
---|
如果其参数的相似度大于由 |
如果第一个参数中的三字母组集合与第二个参数中的连续有序三字母组集合的相似度大于由 |
|
如果其第二个参数具有匹配词语边界的连续有序三字母组集合,并且其与第一个参数的三字母组集合的相似度大于由 |
|
返回参数之间的“距离”,即 1 减去 |
返回参数之间的“距离”,即 1 减去 |
|
返回参数之间的“距离”,即 1 减去 |
|
pg_trgm
模块提供 GiST 和 GIN 索引操作符类,允许您在文本列上创建索引,以实现非常快速的相似度搜索。这些索引类型支持上述相似度运算符,并且还支持基于三字母组的 LIKE
、ILIKE
、~
、~*
和 =
查询的索引搜索。在 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 开始,这些索引类型还支持 LIKE
和 ILIKE
的索引搜索,例如
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 的相对性能特征,这些在别处有讨论。
三字母组匹配是与全文索引结合使用的非常有用的工具。特别是它可以帮助识别全文检索机制无法直接匹配的拼写错误的输入单词。
第一步是生成一个包含文档中所有唯一单词的辅助表
CREATE TABLE words AS SELECT word FROM ts_stat('SELECT to_tsvector(''simple'', bodytext) FROM documents');
其中 documents
是一个具有文本字段 bodytext
的表,我们希望对其进行搜索。使用 simple
配置和 to_tsvector
函数而不是使用特定语言的配置的原因是,我们想要原始(未词干化)单词的列表。
接下来,在单词列上创建三字母组索引
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 <oleg@sai.msu.su>
,莫斯科,莫斯科大学,俄罗斯
Teodor Sigaev <teodor@sigaev.ru>
,莫斯科,Delta-Soft Ltd.,俄罗斯
Alexander Korotkov <a.korotkov@postgrespro.ru>
,莫斯科,Postgres Professional,俄罗斯
文档:Christopher Kings-Lynne
本模块由 Delta-Soft Ltd.(俄罗斯莫斯科)赞助。
如果您在文档中发现任何不正确、与您在该特定功能上的经验不符或需要进一步澄清的内容,请使用 此表单 报告文档问题。