Комментарии 11
Почему именно postgresql выбран для полнотекстового поиска? Раньше он был одним из самых медленных движков полнотекстового поиска. Как в 2024 году он себя показывает в сравнении с elasticsearch, sphinx и т.д.?
на самом деле сравнивать postgresql со специализированным поисковым движком бессмысленно, понятно, что в последнем и скорость и функциональность в среднем будет больше/лучше. Но! Если вы своем приложении используете не самые сложные процессы полнотекстового поиска, то постгрес будет норм выбором, потому что
1/ не потребуется городить доп инфру
2/ не потребуется городить CDC процесс в поисковой движок
3/ не потребуется решать проблемы с нарушением консистентности по сути двух отдельных баз данных (постгреса и, например, эластика)
4/ все будет в одном месте с понятным единообразным апи и простым процессом интеграции в ваше приложение.
Естественно, окончательное решение нужно будет принимать оглядываясь на циферки: нормально ли все фт и нфт закрыты, но для старта постгрес будет очень даже нормальным выбором, как показывает практика внедрения в проектах вокруг (например, Discourse и gitlab).
У эластика в последних версиях вроде бы нет русской морфологии, и плагин с ней не поддерживается. Если я неправ, подскажите как ее подключить.
Вроде как ничего с поддержкой русского языка не изменилось
https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-lang-analyzer.html
Так это стеммеры, прям в документации указано:
"type": "stemmer",
А стеммер не учитывает морфологию и не приводит к нормальной форме, просто сокращает по эвристикам. В реальном применении зачастую бесполезен и неточен.
ну кроме стандартного стеммера для русского языка доступен как минимум сноубол
"russian_snowball": {
"type": "snowball",
"language": "Russian"
}ну естественно стеммер с переопределением. Как мне кажется по сравнению с предыдущими версиями эластика ничего не изменилось. Ну и опять же можно плагин установить, который улучшит морфологический анализ для русского языка
https://github.com/nickyat/elasticsearch-analysis-morphology?tab=readme-ov-file
возможно его потребуется пересобрать под более свежую версию эластика (там в зависимостях стоит Elasticsearch 8.9.1)
И в Dockerfile описано как собранный плагин подключить к Elasticsearch
Если стандартного анализатора русского языка не хватает, то можно попробовать вот этот плагин взять
https://github.com/nickyat/elasticsearch-analysis-morphology?tab=readme-ov-file
возможно его потребуется пересобрать под более свежую версию эластика (там в зависимостях стоит Elasticsearch 8.9.1)
И в Dockerfile описано как собранный плагин подключить к Elasticsearch
А что скажете насчет https://github.com/postgrespro/rum ?
В принципе сложно что-то добавить к статье Егора Рогова, учитывая, что он непосредственно общается с людьми, которые этот индекс спроектировали и знает, как все утроено изнутри :)
https://habr.com/ru/companies/postgrespro/articles/452116/,
Но может какие-то отдельные мои комментарии вам помогут.
Например, в наших задачах RUM предпочтительнее, поскольку нам важно делать ранжирование результатов поисковой выдачи по релевантности при полнотекстовом поиске, используя GIN вы в таких запросах преимуществ никаких не получаете, а вот с RUM все значительно шустрее происходит.
Скажем тут
CREATE TABLE articles (
id serial PRIMARY KEY,
content text,
created_at timestamp
);
CREATE INDEX articles_content_rum_idx ON articles USING rum (to_tsvector('english', content) rum_tsvector_ops);
-- Получаем топ-5 статей по ключевым словам "AI" и "ML"
SELECT id, content
FROM articles
WHERE to_tsvector('english', content) @@ to_tsquery('AI & ML')
ORDER BY content <=> to_tsquery('AI & ML')
LIMIT 5;
RUM индекс выполняет index_scan, чтобы сразу отсортировать и вернуть 5 самых релевантных записей. Для GIN индексам потребовался бы полный скан и сортировка после поиска.
Еще комментируя статью Егора, наверное, отмечу, что у него упоминается возможность использовать RUM для исключающих ограничений> Note that, unlike GIN, RUM supports index scan — otherwise, it would not have been possible to return exactly the required number of results in queries with «limit» clause. There is no need for the counterpart of «gin_fuzzy_search_limit» parameter accordingly. And as a consequence, the index can be used to support exclusion constraints.
Но я кроме как простого полного сравнения tsvector примера придумать не смог (( То есть, например как GIST использовать RUM не получиться, что исключать какие-то куски текста, например
CREATE TABLE documents (
id SERIAL PRIMARY KEY,
content TEXT,
tsv tsvector GENERATED ALWAYS AS (to_tsvector('english', content)) STORED,
EXCLUDE USING rum (tsv WITH =)
);
В данном примере мы создаем исключающее ограничение на поле tsv с использованием индекса RUM. Оператор WITH = указывает, что мы хотим исключить случаи, когда значение tsv совпадает у двух разных записей. Индекс RUM здесь необходим, поскольку он поддерживает операцию равенства на типе tsvector и может эффективно выполнять такое сравнение благодаря возможностям индексного сканирования.
Мы у себя в проекте используем полнотекстовый поиск, и могу добавить на собственном опыте два самых неудобных момента при его использовании:
1) Словари считываются каждую (!) сессию что очень замедляет запросы при больших словарях. Проблема решаема с помощью shared_lspell, но его надо компилировать. Почему это нет "из коробки" - для меня загадка.
2) Так как словари - это, по сути, файлы конфигурации то вносить слова и синонимы очень неудобно. Притом у нас БД - храни все словари в табличке, да радуйся, но нет.
В общем, работать можно, но неудобно.
Информация
- Дата регистрации
- Дата основания
- Численность
- свыше 10 000 человек
- Местоположение
- Россия
- Представитель
- Vatuhaa
Быстрее пули: как найти счастье с PostgreSQL