Гость
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / Как заставить gin индекс брать триграммы не на основе дефолтного collation базы? / 5 сообщений из 5, страница 1 из 1
01.04.2021, 22:08
    #40058971
Как заставить gin индекс брать триграммы не на основе дефолтного collation базы?
В базе данных все таблицы изначально были установлены в порядке сортировки: LC_COLLATE=C и LC_CTYPE = C. Оказалось, что из-за этого поиск игрока по нику не работает для кириллицы. Поэтому я решил изменить правила сортировки для отдельной колонки с ником:

Код: sql
1.
2.
3.
CREATE COLLATION IF NOT EXISTS english (provider = icu, locale = 'en_US');
ALTER TABLE player
    ALTER COLUMN nickname SET DATA TYPE character varying(64) COLLATE "english";



Далее я хотел сделать быстрый поиск игрока по нику с помощью индексов триграмм и создал gin индекс:

Код: sql
1.
2.
CREATE EXTENSION IF NOT EXISTS pg_trgm;
CREATE INDEX CONCURRENTLY player_nickname_idx_gin ON player USING gin (nickname gin_trgm_ops);



После этого поиск по нику значительно ускорился на латинице , и в плане запроса видно, что используется gin индекс.

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
EXPLAIN ANALYSE
SELECT * FROM player
WHERE nickname like '%qwerty%';

QUERY PLAN
"Bitmap Heap Scan on player  (cost=81.19..6172.98 rows=1702 width=266) (actual time=2.788..6.735 rows=580 loops=1)"
"  Recheck Cond: ((nickname)::text ~~ '%qwerty%'::text)"
"  Rows Removed by Index Recheck: 448"
"  Heap Blocks: exact=1021"
"  ->  Bitmap Index Scan on player_nickname_idx_gin  (cost=0.00..80.77 rows=1702 width=0) (actual time=2.446..2.447 rows=1028 loops=1)"
"        Index Cond: ((nickname)::text ~~ '%qwerty%'::text)"
"Planning Time: 0.304 ms"
"Execution Time: 6.869 ms"



Но тот же запрос не работает с кириллицей ...

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
EXPLAIN ANALYSE
SELECT * FROM player
WHERE nickname like '%абвгд%';

QUERY PLAN
"Gather  (cost=1000.00..122898.55 rows=532 width=266) (actual time=190.395..1243.729 rows=27 loops=1)"
"  Workers Planned: 2"
"  Workers Launched: 2"
"  ->  Parallel Seq Scan on player  (cost=0.00..121845.35 rows=222 width=266) (actual time=256.894..1103.830 rows=9 loops=3)"
"        Filter: ((nickname)::text ~~ '%абвгд%'::text)"
"        Rows Removed by Filter: 1773005"
"Planning Time: 0.252 ms"
"JIT:"
"  Functions: 12"
"  Options: Inlining false, Optimization false, Expressions true, Deforming true"
"  Timing: Generation 10.563 ms, Inlining 0.000 ms, Optimization 5.027 ms, Emission 59.776 ms, Total 75.367 ms"
"Execution Time: 1248.374 ms"




Я также попытался установить collation для gin индекса, но ничего не изменилось. Скажите, как заставить gin индекс брать триграммы, не основанные на стандартной сортировке базы? Есть ли какой-нибудь способ избежать перестройки кластера в этой ситуации?
...
Рейтинг: 0 / 0
02.04.2021, 10:56
    #40059024
Alexius
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как заставить gin индекс брать триграммы не на основе дефолтного collation базы?
Евгений Калинин,

а если указать collation и для поля в индексе и для самой поисковой строки в запросе - так не подхватит индекс?
...
Рейтинг: 0 / 0
02.04.2021, 11:45
    #40059043
Как заставить gin индекс брать триграммы не на основе дефолтного collation базы?
Создал новый индекс, дропнув старый:

Код: sql
1.
2.
CREATE INDEX CONCURRENTLY player_nickname_idx_gin ON player USING gin 
(nickname COLLATE public.english gin_trgm_ops);



Попробовал:

Код: sql
1.
2.
3.
explain analyse
select * from player
where nickname like '%абвгде%' COLLATE public.english;



Без изменений:

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
QUERY PLAN
"Gather  (cost=1000.00..134059.97 rows=547 width=260) (actual time=402.362..1215.868 rows=13 loops=1)"
"  Workers Planned: 2"
"  Workers Launched: 2"
"  ->  Parallel Seq Scan on player  (cost=0.00..133005.27 rows=228 width=260) (actual time=345.131..1095.698 rows=4 loops=3)"
"        Filter: ((nickname)::text ~~ '%абвгде%'::text COLLATE english)"
"        Rows Removed by Filter: 1823437"
"Planning Time: 0.299 ms"
"JIT:"
"  Functions: 12"
"  Options: Inlining false, Optimization false, Expressions true, Deforming true"
"  Timing: Generation 10.706 ms, Inlining 0.000 ms, Optimization 4.560 ms, Emission 60.069 ms, Total 75.335 ms"
"Execution Time: 1221.123 ms"
...
Рейтинг: 0 / 0
02.04.2021, 12:06
    #40059051
Как заставить gin индекс брать триграммы не на основе дефолтного collation базы?
Так же заметил, что русский текст не разбивается на триграммы:

Код: sql
1.
2.
SELECT show_trgm('abcd') union 
SELECT show_trgm('абвгд');


Код: sql
1.
2.
{}
{"  a"," ab",abc,bcd,"cd "}
...
Рейтинг: 0 / 0
02.04.2021, 12:59
    #40059084
Maxim Boguk
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как заставить gin индекс брать триграммы не на основе дефолтного collation базы?
Евгений Калинин
Так же заметил, что русский текст не разбивается на триграммы:

Код: sql
1.
2.
SELECT show_trgm('abcd') union 
SELECT show_trgm('абвгд');


Код: sql
1.
2.
{}
{"  a"," ab",abc,bcd,"cd "}



В общем не вылечите вы это без пересоздания базы с нормальными LC_COLLATE/LC_CTYPE
во всяком случае штатными методами.

--
Maxim Boguk
лучшая поддержка PostgreSQL: dataegret.ru
...
Рейтинг: 0 / 0
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / Как заставить gin индекс брать триграммы не на основе дефолтного collation базы? / 5 сообщений из 5, страница 1 из 1
Целевая тема:
Создать новую тему:
Автор:
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]