Как оптимизировать запрос поиска подстроки в Postgres? - PullRequest
0 голосов
/ 20 декабря 2018

У меня есть 2 таблицы одинаковой формы

таблица A: content | text

таблица B: SubContent | text

Таблица B, содержащая подстроку текстов в таблице A

для примера:

Таблица a:

  • zupta.,за делая Южную Африку хуже, чем когда-либо.
  • zur eda terkenang arwah ibu .,эда теркенанг арва ибу..

Таблица B:

  • изготовление Южной Африки
  • terkenang arwah ibu

я хочу добиться:

making south africa | zupta . . for **making south africa** worse than ever.
terkenang arwah ibu | zur eda **terkenang arwah ibu** . . eda terkenang arwah ibu . .

очень простой запрос, который я использовал

select subcontent, content from A join B on  content SIMILAR TO '%'||subcontent||'%'

объяснение запроса:

Gather  (cost=1000.00..6611032.19 rows=1678309 width=180)
  Workers Planned: 2
  ->  Nested Loop  (cost=0.00..6442201.29 rows=699295 width=180)
"        Join Filter: (A.content ~ similar_escape((('%'::text || B.subcontent) || '%'::text), NULL::text))"
        ->  Parallel Seq Scan on A  (cost=0.00..8675.79 rows=186479 width=91)
        ->  Seq Scan on B  (cost=0.00..19.50 rows=750 width=89)

я пытаюсь использовать крупные текстовые индексы подписаться на этот блог (Эндрю Кейн проделал большую работу!)

https://medium.com/@ankane/large-text-indexes-in-postgres-5d7f1677f89f

я пытаюсь добавить индекс наОбе колонки , которые не помогли выполнить, занимают 40 минут, есть идеи?

Объясните после использования Laurenz Albe ответ

Nested Loop  (cost=27.79..100352.93 rows=1678309 width=180)
  ->  Seq Scan on q2_distinct  (cost=0.00..19.50 rows=750 width=89)
  ->  Bitmap Heap Scan on clean_distinct  (cost=27.79..111.40 rows=2238 width=91)
"        Recheck Cond: (A.content ~ similar_escape((('%'::text || q2_distinct.part) || '%'::text), NULL::text))"
        ->  Bitmap Index Scan on "clean_distinct_Post content_idx"  (cost=0.00..27.23 rows=2238 width=0)
"              Index Cond: (A.content ~ similar_escape((('%'::text || B.content) || '%'::text), NULL::text))"

Ответы [ 2 ]

0 голосов
/ 20 декабря 2018

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

Пример запроса.

postgres=# select to_tsvector('english', 'Big cats eat fish on Mondays.') 
               @@ phraseto_tsquery('english', 'eat fish on monday') as query;
 query
-------
 t

Обратите внимание, что множественное число и заглавные буквы Mondays не остановили совпадение.

Используйте функцию to_tsvector для создания проанализированной формы вашего контента, которую вы можете использовать для индекса GIN.

postgres=# select to_tsvector('english', 'Big cats eat fish on Mondays.');
               to_tsvector
---------------------------------------------
 'big':1 'cat':2 'eat':3 'fish':4 'monday':6

Обратите внимание, как to_tsvector нормализует строку (меняется на строчные буквы)удаление знаков препинания, удаление множественного числа и удаление слов с низким значением, таких как «вкл»).Это означает, что «есть рыбу, если понедельник» также будет соответствовать (так как «если» также слово с низким значением).Поэтому вам нужно будет добавить вторую проверку, используя оператор LIKE, если вы хотите только точное совпадение.Но это будет выполняться гораздо реже, чем без индекса tsvector GIN.

Таким образом, ваш запрос теперь будет выглядеть так:

SELECT subcontent, content 
FROM A 
JOIN B ON (
    A.tsv_content @@ phraseto_tsquery(B.lang, B.subcontent) 
    AND content LIKE '%' || subcontent || '%'
);

NB.phraseto_tsquery требуется 9,6 +

0 голосов
/ 20 декабря 2018

Любое объединение, которое не имеет условия объединения с оператором равенства (=), может использовать только объединение с вложенным циклом.

Единственный индекс, который может здесь потенциально помочь, - это индекс триграмм на A:

CREATE EXTENSION pg_trgm;
CREATE INDEX ON "A" USING gin (content gin_trgm_ops);

Но вы не должны ожидать хорошего времени выполнения с таким запросом.

...