网站首页 > 历史论文> 文章内容

Postgres 的全文搜索已经足够好了 - 技术翻译

※发布时间:2016-5-17 16:43:08   ※发布作者:habao   ※出自何处: 

  开发Web应用时,你经常要加上搜索功能。甚至还不知能要搜什么,就在草图上画了一个放大镜。

  搜索是项非常重要的功能,所以像elasticsearch和SOLR这样的基于lucene的工具变得很流行。它们都很棒。但使用这些大规模“杀伤性”的搜索武器前,你可能需要来点轻量级的,但又足够好的搜索工具。

  所谓“足够好”,我是指一个搜索引擎拥有下列的功能:

  由于用post和author分组了,因为有多个tag关联到一个post,我们使用string_agg()作聚合函数。即使author是外键并且一个post不能有多个author,也要求对author添加聚合函数或者把author加到GROUP BY中。

  我们还用了coalesce()。当值可以是NULL时,使用coalesce()函数是个很好的办法,否则字符接的结果将是NULL。

  发生了怪事。首先比原文的词少了,一些词也变了(try变成了tri),而且后面还有数字。怎么回事?

  一个tsvector是一个标准词位的有序列表(sortedlist),标准词位(distinct lexeme)就是说把同一单词的各种变型体都被标准化相同的。

  标准化过程几乎总是把大写字母换成小写的,也经常移除后缀(比如英语中的s,es和ing等)。这样可以搜索同一个字的各种变体,而不是乏味地输入所有可能的变体。

  数字表示词位在原始字符串中的,比如“man出现在第6和15的上。你可以自己数数看。

  Postgres中to_tesvetor的默认配置的文本搜索是“英语“。它会忽略掉英语中的停用词(stopword,译注:也就是am is are a an等单词)。

  这解释了为什么tsvetor的结果比原句子中的单词少。后面我们会看到更多的语言和文本搜索配置。

  如果你需要为每种语言创建无重音的文本搜索配置由Postgres支持,然后你可以使用gist

  我们当前的文档大小可能会增加,因为它可以包括无重音的无用词但是我们并没有关注重音字符查询。这可能是有用的如有人用英语键盘搜索法语内容。

  归类试图处理特定的上下文搜索, 因此有许多个配对的时候,相关性最高的那个会被排在第一个。PostgreSQL提供了两个预定义归类函数,它们考虑到了词释,接近度和结构信息;他们考虑到了在上下文中的词频,如何接近上下文中的相同词语,以及在文中的什么出现和其重要程度。

  --PostgreSQL documentation

  但是, 相关性的概念是模糊的,而且是与特定的应用相关. 不同的应用可能需要额外的信息来得到想要的排序结果,比如,文档的修改时间. 内建的排序功能如asts_rank只是个例子.你可以写出自己的排序函数 并且/或者 将得到的结果和其他因素混合来适应你自己的特定需求.

  这里说明一下, 如果我们想是新的文章比旧的文章更重要,可以讲ts_rank函数的数值除以文档的年龄+1(为防止被0除).

  GIN还是GiST索引? 这两个索引会成为与他们相关的博文的主题. GiST会导出一个错误的匹配,之后需要一个额外的表行查找来验证得到的匹配. 另一方面, GIN 可以更快地查找但是在创建时会更大更慢.

  一个经验, GIN索引适合静态的数据因为查找是迅速的. 对于动态数据, GiST 可以更快的更新. 具体来说, GiST索引在动态数据上是好用的并且如果单独的字(词位)在100,000以下也是快速的,然而GIN 索引在处理100,000词位以上时是更好的但是更新就要慢点了.

  --Postgres文档 : 第12章 全文搜索

  的脚本使用word列创建了一个视图,word列内容来自于词位列表。 我们使用关键字,这样table表中可以存储多种语言的文本。 一旦创建了这个实体化视图,我们需要添加一个索引来使相似度查询速度更快。

  CREATEINDEXwords_idxONsearch_wordsUSINGgin(wordgin_trgm_ops);

  这个查询返回的是这样一个语义,它相似度满足(0.5),再根据输入的samething将其最接近的排在首位。操作符-返回的是参数间的“距离”,而且是一减去similarity()的值。

  当你决定在你的搜索中处理拼写错误的时候,你不会希望看到它(拼写错误)出现在每一个查询中。相反地,当你在搜索无结果时,可以为了拼写错误去查询,并使用查询所提供结果给用户一些。如果数据来自于非正式的通讯,例如:社交网络,可能你的数据中会包含拼写错误。你可以通过追加一个类似的语义到你的tsquery中,来获得一个好点的结果。

  Super Fuzzy Searching on PostgreSQL是一篇很好的关于为拼写错误和搜索Postgres使用三字母组的参考文章。

  在我使用的例子中,使用unique语义的表不会大于2000行,而且我的理解是,如果你有超过1M的文本时使用语义,你将会遇到该方法的性能问题。

  关于MySQL和RDS(远程数据服务)

  这在Postgres RDS上能运行吗?

  所有的示例在RDS上都是可以运行的。 据我所知,RDS搜索特性中唯一的是搜索某些数据时需要访问文件系统,如自定义字典,拼写检查程序,同义词,主题词表。 相关信息见亚马逊aws论坛。

  我使用的是MYSQL数据库,我可以使用内置的全文本搜索功能吗?

  如果是我,我不会去用这个功能。 无需争论,MySQL的全文本搜索功能非常局限。 默认情况,它不支持任何语言的词干提取功能。 我偶然发现一个可以安装的词干提取的函数,但是MYSQL不支持基于索引的函数。

  那么你可以做些什么? 鉴于我们的讨论,如果 Postgres能够胜任你使用的各个场景,那么考虑下把数据库换为 Postgres。 数据库迁移工作可以通过工具如py-mysql2pgsql方便地完成。 或者你可以研究一下更高级的解决方案如 SOLR(基于 Lucene的全文搜索服务器)和 Elasticsearch(基于 Lucene的开源、分布式、 RESTful搜索引擎)。

  我们已经了解了基于一个特殊的文档如何构建一个性能良好且支持多语言的文本搜索引擎。 这篇文章只是一个概述,但是它已经给你提供了足够的背景知识和示例,这样你可以开始构建自己的搜索引擎。 在这篇文章中,我也许犯了一些错误,如果你能把错误信息发送到,我将感激不尽。

  Postgres的全文本搜索特性非常好,而且搜索速度足够快。 这可以使你的应用中的数据不断增长,而无需依赖其它工具进行处理。 Postgres的搜索功能是银弹吗? 如果你的核心业务围绕搜索进行,它可能不是的。

  它移除了一些特性,但是在大部分场景中你不会用到这些特性。 毫无疑问,你需要认真分析和理解你的需求来决定使用哪种搜索方式。

  两种语系特点决定了引擎完全不一样,人又不了解东方语言。 其实加入是不难的,有点C语言基础就可以了,底层接口已经设计好,我们也有不少现成的成熟引擎。对,我也知道,的确现在pgsql全文检索中文方案,也有了好多了~~~ 只是奇怪,为何一直没有接收某个方案,应该不至于没人去写个issue吧~

推荐:

关键词:好搜文档