使用Trigram优化Postgres文本搜索 - Alex Klibisz


在这篇文章中,我们将实现和优化一个基于Postgres Trigrams的文本搜索系统。
我们将从一些基本概念开始,然后基于 890 万条亚马逊评论的数据集定义一个测试环境,然后涵盖三种可能的优化。
我们的搜索将开始非常缓慢,大约 360 秒。通过一些深思熟虑的优化,我们最终将超过 100 毫秒 - 加速约 3600 倍!这些优化不会完美地适用于每个文本搜索用例,但它们至少应该激发一些想法。
 
定义“文本搜索”
出于我们的目的,“文本搜索”定义如下:

  1. 我们有一个包含多个文本列的数据库表。
  2. 用户提供一个输入:一个查询字符串(想想 Google 或 Amazon 搜索框)。
  3. 我们在表中搜索十行,其中至少一列与查询字符串匹配。匹配可以是精确的或模糊的。例如,查询字符串“foobar”是值“foobarbaz”的精确匹配和值“foo bar”的模糊匹配。
  4. 一旦我们找到了十个这样的行,我们就对它们进行评分,根据它们的分数重新排列它们,然后将它们返回给用户。

 
为什么选择 Postgres?
Postgres 是一个无处不在的关系数据库,但像 Solr、Elasticsearch 和 Opensearch 这样的专用搜索系统以文本搜索而闻名。
尽管如此,Postgres 还是提供了一些强大的文本搜索功能,与专用搜索系统相比有几个好处:
  1. 我们避免操作额外的基础设施(例如,Elasticsearch 集群)。
  2. 我们避免在系统之间同步数据(例如,Postgres 到 Elasticsearch)。
  3. 我们避免重新实现重要的功能(例如,多租户授权)。

在 Postgres 和 Elasticsearch 上实现和操作搜索功能后,我目前在它们之间进行选择的启发式方法是:
  • 如果搜索是我们的核心产品,或者我们无法将可搜索的文本放入 Postgres 的共享内存缓冲区,请使用 Elasticsearch 并指定一名工程师进行操作和调整。
  • 否则,Postgres 可能就足够了。至少,我们最终会得到一个能够进一步改进的基线。

作为一个案例研究,Gitlab 公开记录了他们从基于 Postgres trigram 的搜索发展到 Elasticsearch 中的高级搜索的历程。
 
什么是Trigram
Trigram是一个简单的字符串中的三个字符序列。
例如,"hello "中的三个字是{"h"、"he"、"hel"、"ell"、"llo"、"lo"}。
Trigram为字符串的比较提供了一个简单的解决方案:要比较两个字符串,我们可以计算它们共享的Trigram的数量。
例如,"hello "和 "helo "共享4个Trigram。"hello "和 "bye "共享0个。"hello "与 "jello "共享的Trigram数比与 "hi "共享的Trigram数多。但这通常是一个强有力的基准线。
 
为什么不用全文搜索?
Postgres也提供全文搜索。我个人更熟悉基于trigram的搜索,这也是我们在这篇文章中使用trigram的部分原因。

通过对全文搜索的一些实验,我发现该API对自然语言文本(即单词、空格、标点符号)的关注度更窄,而对通用文本(即自然语言文本和产品SKU以及电子邮件地址......)的关注度更低。

不过,这篇文章中的一些优化措施可能会很好地转化为全文搜索。

更多点击标题