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 减去 |
|
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
,我们希望搜索该字段。使用 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 <[email protected]>
,莫斯科,莫斯科大学,俄罗斯
Teodor Sigaev <[email protected]>
,莫斯科,Delta-Soft Ltd.,俄罗斯
Alexander Korotkov <[email protected]>
,莫斯科,Postgres Professional,俄罗斯
文档:Christopher Kings-Lynne
此模块由俄罗斯莫斯科的 Delta-Soft Ltd. 赞助。
如果您在文档中看到任何不正确的内容、与您对特定功能的体验不符的内容或需要进一步说明的内容,请使用 此表单 报告文档问题。