@greefon

Как найти частичные совпадения строки запроса в БД для полнотекстового поиска PostgreSQL?

Задача: при поиске вида "alpha beta gamma ... omega" получать результаты с частичным совпадением (т.е. найдено только одно слово, или несколько слов из запроса) и ранжировать всё это с учетом найденного количества слов и их близости. Больше совпадений - выше ранг. Слова ближе друг к другу - выше ранг.
  • Вопрос задан
  • 1010 просмотров
Решения вопроса 1
ayazer
@ayazer
Sr. Software Engineer
Т.е. сделать свой препарсер, который будет отдавать потом запрос в нормальный парсер, который обрежет словоформы.


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

Дальше это нужно ранжировать. У нас OR, и я не очень понимаю, как будут распределяться веса

если тут нужно МНОГО специфических настроек - лучше сразу смотреть в сторону того-же солра. В постгресе все-же поддержка полнотекстового поиска постолько-поскольку. Для многих задач ее хватает, но я в свое время страдал т.к. постоянно натыкался на стену "а так сделать нельзя". Но в целом хоть как-то постгрес ранжирует +есть возможность ручками подправить веса для ключевых частей. Т.е. для примера

select json_flat_content , ts_rank_cd(json_flat_tsv, 'jzvmw | julva | qxqvh | name | value') r
from my_fulltext_index i
where
	i.json_flat_tsv @@ to_tsquery('simple', 'jzvmw | julva | qxqvh | name | value')
order by r desc


вернет

[{"name": "qtmlx", "value": "jzvmw  vajwq julva  ipsmwtbhki  lhgzr"}, {"name": "fslto", "value": "viykw"}]	0.6
[{"name": "lhnhq", "value": "sxgxh!!daxrh guxux!!kfgtirmgig!!ivqwz"}, {"name": "qxqvh", "value": "qbeli"}]	0.5
[{"name": "cepja", "value": "mrfma"}, {"name": "gwjqa", "value": "csxaf"}]	0.4
[{"name": "val", "value": "TNhmT<KxERm"}]	0.2


ну и да, для запроса "мультфильм | Норштейн | Ежик <-> тумане" может понадобится ручками указать меньший вес для "мультфильм" и больший для "Норштейн". И заодно подумать что делать если в поиске из-за очепятки будет "орНштейн"

+ стоит обратить внимание что постгрес (по крайней мере версии 9.5 и 10.? с которыми я работал) плохо работал с нграмами. а точнее - для этого нужно было ставить доп. плагины и потом все это собирать в кучу. т.е. по"сло:*" найти "слово" можно, но по "ово" найти "слово" - уже нет.

+ возможно нужна будет работа с очепятками

+ я не помню умеет ли постгрес работать с синонимами. Это может быть тоже важно

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

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы