Как сделать быстрый pg_trgm DESC (по убыванию)? - PullRequest
8 голосов
/ 04 июля 2019

У меня есть список из 100 000 предложений в таблице, с pg_trgm Я могу получить самые близкие из моей строки "супер круто" очень быстро с индексом GIN / GIST. Смотрите официальный пример:

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

К сожалению, я хочу наоборот, я бы хотел, чтобы большинство отличалось от первого , но индексы GIN / GIST не используются, когда DESC , поэтому это очень медленно.

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

Как я мог это сделать? Восстановить pg_trgm из исходного кода? Как?

Ответы [ 2 ]

3 голосов
/ 10 июля 2019

Я не думаю, что это вообще можно оптимизировать, если "t" не известно заранее или вы не можете что-то кэшировать.Даже если вы попытаетесь изменить исходные тексты Postgres, скорее всего, вы не увидите никакой выгоды.

В документах оператор <-> является сокращением для сходства (t1, t2).Вы можете индексировать такие оценки, если оба термина известны, поэтому, например, вы можете «CREATE INDEX» этой функции для любой комбинации t1, t2, и она будет работать.Это будет стандартный индекс BTree, и вы можете выполнять менее чем, более или менее любые проверки или упорядочения, которые вы хотите.

Но t2 неизвестно, и поэтому вы не можете создать индекс для любой возможной строки.(Или вы могли бы подделать все возможные комбинации строк в таблице, если их разумное количество)

Если вы не знаете другой термин, как работает сортировка?Ну, потому что вы можете получить для своего слова t1, извлечь все триграммы и узнать, какие строки (приливы) появляются по крайней мере X раз.Это быстро, потому что вам нужно проверить только N триграмм для исходного слова, извлечь идентификаторы кортежей в ведрах, посчитать и отсортировать.

Теперь попробуйте сделать это в обратном порядке: вам нужны все слова без триграмм вобщий на всех.Таким образом, вы должны отсканировать полученные триграммы, получить идентификаторы кортежей, а затем извлечь всю таблицу, отфильтровывая идентификаторы кортежей, которые вы получили ранее.И после этого продолжайте с теми, у кого только 1 триграмма, затем 2 и так далее.Это звучит действительно неэффективно, как сканирование всей таблицы и индексация один или два раза.

Основная проблема заключается в получении совпадений с нулевыми совпадениями.Независимо от того, как вы это делаете, вам нужно сканировать всю таблицу.

Если вы можете пропустить хотя бы те из них с нулевым совпадением, то вы можете ускорить этот поиск.Для этого вы можете использовать set_limit (0.0001) и использовать оператор «%» для их фильтрации.(Но не похоже, что это то, что вы хотели)

Даже извлечение триграмм в массив или подтаблицу, похоже, не помогает.Ваша проблема похожа на фильтр Блума, но полностью изменена, и все же я не уверен, что вообще возможно создать такой индекс.

Возможно, если вы добавите больше информации о том, что вы пытаетесь выполнить, мыможно найти другой путь без использования триграмм.

0 голосов
/ 04 июля 2019

Я хотел бы предложить

select * 
from ( 
  SELECT  row_number() OVER () as rk, t, 'super cool' <-> t AS dist   
  FROM test_trgm
) sub  
ORDER BY rk DESC LIMIT 10;
...