8

我在一个表中有一个包含 100.000 个句子的列表,使用pg_trgm我可以使用 GIN/GIST 索引非常快地获得我的字符串“super cool”中最接近的句子。见官方例子:

https://www.postgresql.org/docs/11/pgtrgm.html

可悲的是,我想要相反,我想要最不同的一个,但是DESC时不使用 GIN/GIST 索引,所以它很慢。

SELECT t, 'super cool' <-> t AS dist
  FROM test_trgm
  ORDER BY dist DESC LIMIT 10;

我怎么能那样做?从源代码重建pg_trgm?如何 ?

4

2 回答 2

3

我认为这根本无法优化,除非事先知道“t”或者你可以缓存一些东西。即使您尝试更改 Postgres 源,也很可能根本看不到任何好处。

在文档中,<-> 运算符是相似度(t1,t2)的简写。如果这两个术语都已知,您可以索引这些分数,例如,您可以为任何 t1、t2 组合“创建此函数的索引”,它会起作用。这将是一个标准的 BTree 索引,您可以执行小于、大于或任何您想要的检查或排序。

但是 t2 是未知的,因此,您不能为任何可能的字符串创建索引。(或者,如果数量合理,您可以在表格中伪造所有可能的字符串组合)

如果您不知道另一个术语,排序是如何工作的?好吧,因为您可以获得单词 t1,提取所有三元组,并获得哪些行(tid)至少出现 X 次。这很快,因为您只需检查原始单词的 N 个三元组,检索桶中的元组 id,计数和排序。

现在试着反过来做:你需要所有没有共同三元组的单词。因此,您必须扫描检索到的三元组,获取元组 id,然后获取整个表,过滤掉您之前获得的元组 id。然后继续那些只有 1 个三元组的,然后是 2 个,依此类推。这听起来真的很低效,就像扫描整个表和索引一两次。

主要问题依赖于以零重合检索匹配。不管怎么做,都需要扫描整个表。

如果您至少可以跳过那些符合率为零的,那么您可以加快搜索速度。为此,您可以使用 set_limit(0.0001) 并使用“%”运算符将它们过滤掉。(但听起来这不是你想要的)

即使将三元组提取到数组或子表中似乎也无济于事。您的问题看起来像一个布隆过滤器,但相反,我仍然不确定是否有可能创建这样的索引。

也许如果你添加更多关于你想要完成什么的信息,我们可以在不使用三元组的情况下找到一种不同的方法。

于 2019-07-10T14:39:53.853 回答
0

我想提议

select * 
from ( 
  SELECT  row_number() OVER () as rk, t, 'super cool' <-> t AS dist   
  FROM test_trgm
) sub  
ORDER BY rk DESC LIMIT 10;
于 2019-07-04T08:13:17.660 回答