9.3 9.4 9.5 9.6 10 11
问题报告 纠错本页面

F.30. pg_trgm

pg_trgm模块提供用于决定基于 trigram 匹配的字母数字文本相似度的函数和操作符,以及支持快速搜索相似字符串的索引操作符类。

F.30.1. Trigram(或者 Trigraph)概念

一个 trigram 是从一个字符串中取出的由三个连续字符组成的组。 我们可以通过对两个字符串之间共享的 trigram 计数来测量它们的相似度。 这种简单的思想已经成为在很多自然语言中度量词相似度的有效方法。

注意: 在从一个字符串中提取trigram 时,pg_trgm会忽略非词字符 (非字母数字)。在决定字符串中所含的 trigram 集合时, 每一个词被认为具有两个空格前缀和一个空格后缀。例如, 字符串"cat"中的 trigram 集合是: " c"" ca""cat"以及 "at "。 字符串"foo|bar"中的 trigram 集合是: " f"" fo""foo""oo "" b"" ba""bar"以及 "ar "

F.30.2. 函数和操作符

pg_trgm模块所提供的函数在 表 F-23中显示,提供的操作符在 表 F-24中显示。

表 F-23. pg_trgm 函数

函数返回描述
similarity(text, text)real 返回一个数字指示两个参数有多相似。该结果的范围是 0(指示两个字符串完全不相似) 到 1(指示两个字符串完全一样)。
show_trgm(text)text[] 返回一个给定字符串中所有的 trigram 的数组(实际上除了调试很少有用)。
show_limit()real 返回%操作符使用的当前相似度阈值。例如, 这将两个单词之间的最小相似性设置为被认为足够相似以致彼此拼写错误。
set_limit(real)real 设定%操作符使用的当前相似度阈值。该阈值必须介于 0 和 1 之间 (默认为 0.3)。返回传递进来的相同值。

表 F-24. pg_trgm 操作符

操作符返回描述
text % textboolean 如果它的参数的相似度高于set_limit设置的当前相似度阈值, 则返回true
text <-> textreal 返回参数之间的"距离",即 1 减去similarity()值。

F.30.3. 索引支持

pg_trgm模块提供了 GiST 和 GIN 索引操作符类, 这允许你在一个文本列上创建索引用于快速相似度搜索的目的。 这些索引类型支持上述的相似度操作符,并且额外支持基于 trigram 的索引搜索用于 LIKEILIKE~~*查询。 (这些索引不支持等值或简单比较操作符,因此你可能还需要一个普通的 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);

此时,你将有一个在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 索引无法做到。 当只想要少数最接近的匹配时,这通常会比第一种形式更好。

PostgreSQL 9.1 开始,这些索引类型也支持用于 LIKEILIKE的索引搜索,例如

SELECT * FROM test_trgm WHERE t LIKE '%foo%bar';

该索引搜索通过从搜索字符串中提取 trigram 并且在索引中查找它们来工作。 搜索字符串中的 trigram 越多,索引搜索的效率越高。不像基于 B-树的搜索, 搜索字符串不需要是左锚定的。

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

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

该索引搜索通过从正则表达式中提取 trigram 并且在索引中查找它们来工作。 搜索字符串中的 trigram 越多,索引搜索的效率越高。不像基于 B-树的搜索, 搜索字符串不需要是左锚定的。

对于LIKE和正则表达式搜索,记住没有可提取 trigram 的模式将退化成一个全文索引扫描。

选择GiST还是GIN索引取决于GiST和GIN的相对性能特征,这在其他地方讨论。 一般来说,搜索 GIN 索引比 GiST 索引更快,但是在构建或者更新时要慢。 所以 GIN 更适合于静态数据,而 GiST 更适合于经常更新的数据。

F.30.4. 文本搜索集成

在与一个全文索引联合使用时,trigram 匹配是一个非常有用的工具。 特别是它能有助于识别拼写错误的输入词,这些词直接用全文搜索机制是不会被匹配的。

第一步是生成一个包含文档中所有唯一词的辅助表:

CREATE TABLE words AS SELECT word FROM
        ts_stat('SELECT to_tsvector(''simple'', bodytext) FROM documents');

其中documents是一个具有我们希望搜索的文本域 bodytext的表。对to_tsvector函数使用 simple配置而不是使用语言特定的配置的原因是,我们想要一个原始 (没有去掉词根的)词的列表。

接下来,在词列上创建一个 trigram 索引:

CREATE INDEX words_idx ON words USING GIN(word gin_trgm_ops);

现在,类似于前面例子的一个SELECT 查询可以被用来为用户搜索术语中的拼写不当的词建议拼写。 有用的额外测试是要求所选择的词也具有与拼写错误的词相似的长度。

注意: 由于words表已经被生成为一个单独的、静态的表, 它将需要定期地重新生成,这样它能合理地与文档集合保持一致。 但是保持它完全与文档集合同步通常是不必要的。

F.30.5. 参考

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

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

F.30.6. 作者

Oleg Bartunov ,俄罗斯莫斯科大学

Teodor Sigaev ,俄罗斯莫斯科 Delta-Soft 有限责任公司

文档:Christopher Kings-Lynne

这个模块由俄罗斯莫斯科 Delta-Soft 有限责任公司赞助的。