Задать вопрос

Как организовать пагинацию, если БД и поисковая машина — это раздельные сервисы?

Доброго всем времени.

Каким образом можно организовать пагинацию запросов, фильтрованных одновременно по полнотекстовому запросу и некоторым аргументам, если поисковая машина для полнотекстового поиска и база данных - это раздельные сервисы? В упор не замечаю решения, хотя такое чувство, что оно совсем рядом.

Подробности:
MySQL-сервер (MariaDB 10.3+), в котором хранятся записи вида Документ с огромным набором параметров, по которым можно их отфильтровать - это и many-to-many отношения (фильтрация по нескольким ID других моделей), и "больше чем/меньше чем" по столбцу, IS TRUE/FALSE, сравнение строк и так далее. У всех Документов есть особенность - каждому из них соответствует текстовое содержимое, по содержимому которого и необходимо одновременно с поиском по параметрам выполнять фильтрацию. Содержимое хранится в Sphinx / Manticore (поисковые машины). Проблема - организация пагинации.

К примеру, необходимо сделать выборку документов по запросу:
атрибут1 IN (1,2,3)
атрибут2 = 'example_string'
атрибут3 IS TRUE
атрибут4 > 500
запрос полнотекстового поиска "укрепляющий эфирный шампунь с экстрактом масел жожоба"

Что ожидается: отфильтрованный по всем параметрам список документов, отсортированный по релевантности, заданной поисковой машиной.

Проблема: пагинация.

В текущем варианте из поисковой машины забираются все айдишники и позже добавляются в запрос базы данных вида WHERE IN (список ID) AND ORDER BY FIELD(id, список ID). Проблема в том, что по любому запросу из поисковой машины находится больше 100 000 документов и при попытке их вернуть поисковая машина выполняет запрос довольно долго (1-2 секунды). После этого еще и сама БД с таким уточнением работает дольше, чем если бы эти данные просто joinились с другой таблицей.

Обратный вариант - брать отфильтрованный список ID из базы данных и формировать условие в поисковой машине WHERE IN (список ID) тоже не вариант - опять низкая скорость обработки (да и кол-во их там переваливает за 100 000 на запрос).

Какие варианты пробовались:
- FEDERATED / FEDERATEDX таблица - не удалось "приготовить", нестабильная работа и на любой чих-ошибку не найти ответ в сети
- SphinxSE таблица - аналогично, отмечен разработчиками как устаревший и неподдерживаемый вариант
- заносить все параметры для фильтрации в индекс поисковой машины - ужасный вариант, так как поисковая машина выполняет фильтрацию по обычным своим полям очень медленно, плюс встает необходимость содержать актуальными две копии данных - в БД и поисковой машине
- PostgreSQL с полнотекстовым поиском - слабый поиск по русским словам и очень малое количество информации по тому, как использовать

Документов в базе в общем около 100 миллионов. Нужна скорость. Почему считаю, что она может быть? Потому что любой сложный запрос со стороны БД выполняется менее чем за 0.15 с, в поисковой машине - тоже около 0.15с. А соединить результаты их фильтрации черт знает как. Пробовался еще вариант "вычислять пересечения ID из двух результатов", но тут поисковая машина становится узким местом - не умеет она быстро отдавать все найденные ID, если их число переваливает за 1000 (кто пользуется Sphinx / Manticore, должен знать эту особенность).

Ограничение: поисковая машина должна быть обязательно Sphinx / Manticore. Остальные - болезненно некачественный поиск по тому содержимому, что есть в документах.
  • Вопрос задан
  • 989 просмотров
Подписаться 10 Сложный 1 комментарий
Решение пользователя Boris Köln К ответам на вопрос (4)
@BorisKorobkov Куратор тега MySQL
Web developer
Все атрибуты надо индексировать / фильтровать поисковой машиной.
sphinxsearch.com/docs/current.html#attributes
Ответ написан