搜索长字符串时如何在 Postgres 中实现 sub 1s Trigram/Vector 搜索

问题描述 投票:0回答:1

我正在编译一个大小合适的文档数据库(从 20 到 500 个字符不等),我希望能够非常快速地(不到 1 秒)搜索它们。

我从大约 10 万行数据开始,现在大约有 400 万行。我计划将其限制在 3000 万行左右。

在项目开始时,我使用 Postgres 的 全文搜索pg_trgm 编写了一个快速搜索查询,从效率和准确性的角度来看效果非常好。在 4M 行全文搜索仍然在毫秒级,但trigram 搜索有时需要超过 2 分钟

这里是查询:

SELECT text
FROM my_table
WHERE text_vector @@ websearch_to_tsquery('simple', 'a string to search')
OR text_vector @@ websearch_to_tsquery('english', 'a string to search')
OR 'a string to search' <<% text
LIMIT 100;

我们在插入时存储和索引

ts_vector
s,这使我们能够直接在全文搜索中使用
text_vector

之所以加入八卦搜索是因为我想要某种模糊搜索。使用全文搜索搜索“robots”之类的东西效果很好,但是“robot contests”或“cool robot pics”会漏掉很多相关结果,因为它们并不完全匹配。我不太关心查询的 100% 准确度,而更关心的是给出数据库中结果的 good general picture。我也不关心返回多少结果,只关心与查询最相似的 100 个。我的思路是,让全文搜索匹配前n的结果,模糊搜索填充后面的100 - n

我已经根据Postgres的推荐为全文搜索和三元搜索添加了适当的索引。 卦指数显然很大,我们希望它随着我们添加越来越多的值而不断变大。

我不是 Postgres 专家,但根据我的研究,我认为我的主要问题可能是数据库没有使用足够的计算来快速使用 trigram 索引。我试过增加数据库的统计数据,如

shared_buffers
work_mem
effective_cache_size
,但由于某种原因没有效果。我在一个有 2 个 CPU 和 4GB RAM 的实例上运行数据库,而这个数据库是唯一在上面运行的东西,所以我想最大化计算。

我问这个问题主要是为了在比我更了解 Postgres 的人之间展开讨论,看看我可以采取哪些步骤对 Postgres 进行模糊搜索,将速度放在首位。我也研究过像 pgvector 这样的扩展来尝试获得相同的结果,但我认为问题仍然存在,因为索引太大而无法足够快地进行搜索。

我的主要问题是:

  1. 如果我只是“扔硬件”解决问题,我能否始终将这些搜索结果保持在 1 秒以下?我不介意得到一个更大的实例,只要我知道它可以很好地处理三元组或矢量搜索。
  2. 我可以用我现在拥有的实例大小(2 个 CPU,4GB RAM)实现我想要的吗?如果是这样,我该如何调整我的数据库设置?
  3. 是否有一些我不知道的简单实现技巧/优化?
  4. 我正在搜索的字符串是否太大而无法足够快地进行三元组/向量搜索?
  5. Postgres 是解决这个问题的正确工具吗?如果没有,有没有想到更好的工具?

如果这是一个复杂的问题,我有一些关于如何以不同方式加速搜索的想法。但是按照 KISS 方法,我想在深入研究更复杂的解决方案之前尝试使用 Postgres 进行简单的相似性/矢量搜索。我对 Postgres 比较陌生,并且知道它已经存在了一段时间,我想接触有经验的用户并确保我以正确的方式进行。

编辑: 以下是

text
text_vector
列的定义:

text TEXT NOT NULL

text_vector tsvector GENERATED ALWAYS AS (to_tsvector('english', "text")) STORED

还有我用的索引

CREATE INDEX trgm_idx ON my_table USING GIST (text gist_trgm_ops);
database postgresql search full-text-search pg-trgm
1个回答
0
投票

也许你只是创建了错误的索引;很难说,因为你没有显示你的对象定义。

但我要说的是,对于三元组索引,全文搜索或多或少是多余的:任何与全文搜索匹配的东西都应该足够相似。既然你说你想要 100 个最相似的条目,你可以使用 GiST 索引和查询如下:

CREATE INDEX ON my_table USING gist (text gist_trgm_ops);

SELECT text
FROM my_table
WHERE 'a string to search' <<% text
ORDER BY 'a string to search' <<<-> text
LIMIT 100;
© www.soinside.com 2019 - 2024. All rights reserved.