使用 Postgres 全文搜索搜索完全匹配的最佳方法是啥?

Posted

技术标签:

【中文标题】使用 Postgres 全文搜索搜索完全匹配的最佳方法是啥?【英文标题】:What is the best way to search for an exact match using Postgres full-text search?使用 Postgres 全文搜索搜索完全匹配的最佳方法是什么? 【发布时间】:2016-08-02 01:13:26 【问题描述】:

我有一个包含大约 150 万条记录的 Postgres 数据库。在我的 Ruby on Rails 应用程序中,我需要搜索 statement_text 字段(可以包含 1 到数百个单词)。

我的问题:我知道我可以使用pgSearch gem 来创建像search_all_wordssearch_any_words 这样的范围,但我不确定确保只有完全匹配的记录的最有效方法是什么 在结果集中返回。

也就是说,如果我搜索“教皇弗朗西斯”,我希望它只找到连续且顺序相同的这两个词(而不是说,“教皇名叫弗朗西斯”)。

到目前为止,我刚刚将 GIN 索引与 ILIKE 结合起来进行精确匹配搜索。但是考虑到 GIN 索引在每条记录中基本上都由storing the exact position of a word 起作用,难道不应该有更有效的(非ILIKE)方法来确保搜索词与字段完全匹配吗?

【问题讨论】:

【参考方案1】:

一般来说,全文需要根据所使用的语言词典进行词干提取,因此使用全文搜索可以使用 ts_rank() 函数而不使用 词干'simple' 词典来确定您正在搜索的短语的相关性。

WITH t(v) AS ( VALUES
  ('Test sentence with Pope Francis'),
  ('Test Francis sentence with Pope '),
  ('The pope is named Francis')
)
SELECT v,ts_rank(tsv,q) as rank
FROM t,
    to_tsvector('simple',v) as tsv,
    plainto_tsquery('simple','Pope Francis') AS q;

结果:

                v                 |   rank    
----------------------------------+-----------
 Test sentence with Pope Francis  | 0.0991032
 Test Francis sentence with Pope  | 0.0973585
 The pope is named Francis        | 0.0973585
(3 rows)

没有全文搜索,您可以使用pg_trgm 扩展名实现更快的ILIKE 模式匹配。例如here

【讨论】:

谢谢,德米特里!我正在使用全文搜索,所以我可以使用 ts_rank。但是,问题在于——取决于字段的字数——没有特定的截止点可以确保单词相邻且顺序正确,而无需使用 ILIKE。我理解正确吗? 不,没有基于长度的截断。如果短语匹配,它仍然会有更高的排名。您可以省略 ts_rank 的归一化因子 - 它应该可以正常工作。

以上是关于使用 Postgres 全文搜索搜索完全匹配的最佳方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章

关于全文搜索elasticsearch中matchQuery和termQuery的区别

云服务器上Postgres全文搜索的进一步优化

全文本搜索

搜索比较前缀的最佳匹配

Mysql Search - 用于全文搜索的 InnoDB 和事务与 MyISAM

iOS 中的全文子字符串搜索