我正在编译一个大小合适的文档数据库(从 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 这样的扩展来尝试获得相同的结果,但我认为问题仍然存在,因为索引太大而无法足够快地进行搜索。
我的主要问题是:
如果这是一个复杂的问题,我有一些关于如何以不同方式加速搜索的想法。但是按照 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);
也许你只是创建了错误的索引;很难说,因为你没有显示你的对象定义。
但我要说的是,对于三元组索引,全文搜索或多或少是多余的:任何与全文搜索匹配的东西都应该足够相似。既然你说你想要 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;