利用 PostgreSQL 实现毫秒级全文检索

  • 2015-05-13
  • 本文字数:843 字

    阅读完需:约 3 分钟

Lateral 是一家内容推荐服务提供商,其模拟程序使用 PostgreSQL 存储文档。每个文档包含一个 text 列和一个存储标题、日期和 URL 等元数据的 JSON 列。他们希望为模拟程序创建快速搜索功能,搜索文档全文和标题,生成推荐内容。近日,Lateral 首席技术官 Max撰文介绍了他们的做法。

为了实现这一目标,可以选择开源解决方案 Apache Solr Elasticsearch ,也可以选择托管解决方案 Elastic Algolia ,但出于以下考虑,他们选择了 PostgreSQL 的全文搜索功能

  • 不需要额外安装软件或库
  • 可以重用他们在应用程序中使用的数据库接口
  • 不需要配置额外的服务器
  • 不增加成本
  • 数据可以存储在可控的地方
  • 不需要在不同的数据源之间同步数据

虽然 PostgreSQL 搜索的精度和大规模查询速度存在缺陷,但 Max 认为,它可以满足他们的应用场景。以下是他们的做法:

  1. 创建一个列 tsv,存储 tsvector 值;
  2. 在新建的列上创建索引,并用下面的语句填充列:
 UPDATE data_rows SET tsv
 =setweight(to_tsvector(coalesce(meta->>'title','')), 'A') 
 ||setweight(to_tsvector(coalesce(text,'')), 'D');
 

此处需要注意,JSON 列的权重为 A,text 列的权重为 D;
3. 创建 tsv 列更新函数;
4. 在表上创建触发器,当更新和新增行时,执行 tsv 列更新函数。

当一切就绪后,替换下面代码中的“你的查询”并执行:

SELECT id, meta->>'title' as title, meta FROM (
 SELECT id, meta, tsv
 FROM data_rows, plainto_tsquery('你的查询') AS q
 WHERE (tsv @@ q)
) AS t1 ORDER BY ts_rank_cd(t1.tsv, plainto_tsquery('你的查询')) DESC LIMIT 5;

经测试,该查询大约 50 毫秒即可完成。如果返回文档全文,则会增加大约 350 毫秒,这更多的可能是受网络负载影响。如果只返回文档中的 200 个字符,则仅仅增加大约 100 毫秒。


感谢崔康对本文的审校。

给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家通过新浪微博( @InfoQ @丁晓昀),微信(微信号: InfoQChina )关注我们,并与我们的编辑和其他读者朋友交流(欢迎加入 InfoQ 读者交流群InfoQ 好读者)。