Pull to refresh

Sphinx — не только для поиска!

Reading time2 min
Views10K

Думаю, про такой замечательный поисковый движок Sphinx слышали все или почти все. Наверняка многие уже применяют его, для поиска по сайту, для выборки похожих статей, новостей, товаров и т.д. Он отлично справляется с поисковыми задачами даже на очень больших количествах записей. Но, в своей статье я хочу рассказать про использование Sphinx не для поиска.

Так получилось, что я продолжил разработку сайта агрегатора новостей. Когда я приступил к нему — он «держал» в базе 40 — 60 тыс. новостей и жутко тормозил. Переписав все с нуля, переведя часть сайта на статику и введя кэширование удалось увеличить количество новостей, с которыми справлялся сайт, приблизительно до 500 тыс. Конечно же, для поиска по новостям я применил Sphinx, так как слышал много восторженых отзывов о нем от коллег. Надо сказать и меня он не разочаровал.

И вот, в один не такой уж прекрасный день, руководство поставило следующую задачу: показывать по одной последней новости из каждого источника. Говоря языком SQL — это сортировка по дате и группировка по источнику. Попытка реализовать соответствующую выборку из базы привела к тому, что сайт стал не справляться с нагрузкой.

Оказалось, что MySQL сначала выполняет группировку (при этом берет первую попавшуюся запись в таблице) и только потом сортирует выбранные записи. Решить проблемму «sort before group» можно либо с помощью подзапроса, либо испольуя агрегирующую функцию MAX(). А это — использование временной таблицы и очень медленно работающие запросы…

Альтернативным решением было использование возможностей Sphinx по группировке результатов. Прочитав документацию, я решил попробовать заменить MySQL в задаче выборки новостей для отображения на сайте на Sphinx.

Для этого пришлось установить сортировку по дате, группировку по числовому полю ID Источника, а в качестве запроса — имя категории новостей. Запрос выглядит следующим образом:
$sphinx = new SphinxClient();
$sphinx->SetServer('localhost', 3312);

$sphinx->SetMatchMode(SPH_MATCH_EXTENDED2);
$sphinx->SetSortMode(SPH_SORT_ATTR_DESC, 'date');
$sphinx->SetLimits($from,$count);
$sphinx->SetGroupBy('site_id', SPH_GROUPBY_ATTR, 'date desc');
$category = "@category_path {$cat['category_path']}";
$result = $sphinx->Query($category, 'news news_delta');


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

Для поддержки индекса в актуальном состоянии используется дельта-индекс, обновлемый каждые 10 минут, и основной индекс, обновляемый ежесуточно. Разгрузка MySQL помогла избежать блокировок таблиц во время выполнения длительных запросов, MySQL используется только для выборки данных по ID, которая происходит очень быстро.
Tags:
Hubs:
+54
Comments31

Articles