Sphinx и его применения для поиска в БД Андрей Аксенов shodan@shodan.ru Поиск в БД – зачем? • Популярные СУБД недостаточно хорошо справляются с задачей поиска (в широком смысле) • В частности, с полнотекстовым поиском – Скорость поиска – Скорость обновления таблицы – Релевантность • В некоторых случаях, есть проблемы даже с “обычными” выборками – Подробности во второй части доклада Поиск в БД – как? • Sphinx – Система для организации полнотекстового поиска – Бесплатная – Открытая (open-source, GPL) – Изначально разработана для интеграции с БД • О чем мы расскажем – Краткий обзор внутреннего устройства – Краткий обзор возможностей – Краткий обзор практических применений Sphinx. Общие сведения • Две основных программы – indexer, получает данные из источников (БД) и строит полнотекстовый индекс – searchd, отвечает на поисковые запросы при помощи построенных indexer-ом индексов • Набор API для разных языков – Легковесные нативные клиенты к searchd – PHP, Python, Ruby, Perl, Java… • SphinxSE – Встраиваемый в MySQL клиент – Storage engine для MySQL 5.0.x и 5.1.x Sphinx. Терминология • Документы Sphinx аналогичны записям в базе данных – Документ это набор текстовых полей и численных атрибутов плюс уникальный ID – аналог строки в таблице БД – Набор полей и атрибутов не меняется в пределах индекса – аналог таблицы в БД – По полям можно вести полнотекстовый поиск – По атрибутам можно дополнительно фильтровать, сортировать, группировать результаты поиска Sphinx. Установка и использование • Установка – ./configure && make && make install – vi sphinx.conf – ./indexer myindex – ./searchd • Использование – include ( “sphinxapi.php” ); – $cl = new SphinxClient (); – $res = new $cl->Query ( “test”, “myindex” ); Sphinx. Устройство индексов • Полнотекстовые индексы хранятся в FS • Имеют специально обученный формат • Формат монолитный, обновление данных производится построением “с нуля” • Проблема, но далеко не смертельная – Быстрая скорость индексации (4-8 MB/sec) – Partitioning индексов для снижения lag – Принципиально отсутствует фрагментация индекса – Атрибуты можно обновлять в реальном времени Чуть подробнее про partitioning • В простейшем случае, делаем 2 индекса для индексации одной и той же “таблицы” – Редко обновляемый main, содержащий основную массу данных – Часто обновляемый delta, содержащий обновления с момента последней индексации delta • Зачастую, схема идеально согласуется с характером изменений данных – Форумы, блоги, mail/news архивы… Источники данных • В общем случае “откуда угодно” – Встроенные “драйвера” для MySQL, Postgres, XML файлов специального формата • Источники разного типа можно комбинировать в одном индексе • Данные для индексации поступают не из таблицы, а из выборки • Т.е. можно делать дополнительную обработку в момент выборки – JOIN-ы, выбирать любой поднабор полей, итд. Sphinx. Спец-возможности • Помимо “просто” полнотекстового поиска, Sphinx умеет много гитик: – Поиск и ранжирование с учетом позиций слов и близости фраз – Произвольные атрибуты, в том числе MVA – Сортировка, фильтрация, группировка – Выдержки с подсветкой ключевых слов – Распределенный поиск – Оптимизация “близких” запросов – Географическое расстояние (geo-distance)… Ранжирование с учетом фраз • Типичный подход – ранжирование только на основании статистики по словам • На больших коллекциях или не очень редких ключевых словах – работает плохо • Основной фактор ранжирования Sphinx – max длина совпадения части фразы запроса с документом • Точные цитаты ранжируются выше всего, качество “в целом” субъективно лучше • Место для роста – quorums, frequencies… Поддержка атрибутов • Произвольное количество численных (либо 1-32 bit unsigned integer, либо float) атрибутов • Необходимы для эффективной (!) фильтрации, сортировки, группировки результатов поиска • Иначе (при хранении в БД), уже при 10100K найденных документов получается неприемлемо медленно • Extern, Inline, MVA Сортировка и фильтрация • Сортировка – По комбинации атрибутов (“@weight desc, user_rank desc”) – Всегда оптимизируется с учетом top-N запрошенных документов • Фильтрация – До 10+ раз быстрее, чем на стороне БД – 3 вида фильтров: 1) набор значений, 2) диапазон значений, 3) geodistance – Произвольное количество фильтров – Exclude-фильтры Группировка • Бывает интересна агрегированная информация о результатах поиска • Для этого в Sphinx сделана группировка • Важное отличие – может быть неточной! – Исполняется в фиксированной памяти – Между распределенными узлами передаются только агрегатные значения – На практике, можно аккуратной настройкой добиться точных значений • Зачастую, абсолютная точность не важна • Можно выбирать лучший элемент в группе Распределенный поиск • Last but not least… • Распределенные индексы позволяют параллельно запускать поиск на нескольких машинах – Запустили удаленные запросы – Последовательно обыскали локальные индексы – Считали все удаленные результаты – Объединили их вместе и вернули клиенту • Можно использовать для multi-core Пример 1.1. “Просто” поиск • • • • • Mininova.org Заменили MySQL FT slaves 300-500K rows, 300-500 MB, 4-5 M q/day Индексируем префиксы, а не сами слова Long query tail – top-N запросов в кэше на стороне приложения (20-30% из кэша, самый частый ~1-2%) • 2 сервера с полными репликами индекса • Loadavg (теперь) около 0.3-0.4 Пример 1.2. “Просто” поиск • • • • • • Boardreader.com 1B rows, 1.5 TB, 700K-1M q/day 6 серверов, 4xCPU + 16 GB RAM + 0.5 TB 4 копии searchd вместо одной (startup, HA) 4 “обычных” HDD вместо RAID (быстрее!) Активный partitioning по времени – Отдельные индексы 1-week, 3-month, all-time • Распределенное “горячее” обновление версии – Критична обратная совместимость – В любой момент отсутствует ~1/24 документов Пример 2. “Обычные” выборки • • • • Sahibinden.com 400K rows, 500M, 3M q/day 99 полей, проблема с MySQL индексами Sphinx использован и для полнотекстовых поисков, и “обычных” выборок – Добавляется ряд keywords при индексации – Оказалось быстрее и удобнее, чем MySQL… – Частая быстрая переиндексация, 9-15 секунд раз в 1 минуту на одном из 8+ CPUs • PHP API overhead стал значимым – Сделали 2 индекса, на 34 и 99 атрибутов Пример 3. Группировка • Boardreader.com • Потребовались отчеты по ссылкам – top доменов, на/с которых ссылались, и т.п. • 150-200 Mrows, 50-100 GB data, 60-100 Kq – Запросы строго с группировкой и сортировкой по COUNT / COUNT DISTINCT – Много входных rows (1-10 M), при этом небольшой result set – Абсолютная точность не требуется • MySQL исполнял прототипы до 300 секунд • Распараллелили при помощи Sphinx Пример 3. Группировка (cont’d) • Группировка на 6x4 CPU кластере – Параллельно с другой нагрузкой – Распределенно, быстро, почти точно • Предобработка индексируемых данных – UDF для выделения всех “интересных” подстрок в отдельные “слова” • Потребовались доработки – COUNT DISTINCT – 64-bit ids (из-за схемы нумерации и коллизий) • Место для оптимизаций – Поскольку релевантность не важна… Пример 4. MVA выборки • • • • • Grouply.com N миллионов сообщений, M тегов Интересные применения для MVA “Официальное” для фильтрации по тегам Для экономии SQL выборок – БД сильно раздроблена на несколько физических серверов – JOIN в общем случае… нелегок – MVA для агрегации (в момент индексации), хранения, возврата ряда значений Выводы • Sphinx, понятно, не панацея • Однако, для довольно широкого круга задач – неплохой выбор • Кстати, ряд возможностей остался за бортом доклада… • Пробуйте! • Заходите – http://sphinxsearch.com/ • Пишите – shodan@shodan.ru