Sphinx и его применения для поиска в БД Андрей Аксенов
Поиск в БД – зачем? Популярные СУБД недостаточно хорошо справляются с задачей поиска (в широком смысле) В частности, с полнотекстовым поиском –Скорость поиска –Скорость обновления таблицы –Релевантность В некоторых случаях, есть проблемы даже с обычными выборками –Подробности во второй части доклада
Поиск в БД – как? 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) атрибутов Необходимы для эффективной (!) фильтрации, сортировки, группировки результатов поиска Иначе (при хранении в БД), уже при K найденных документов получается неприемлемо медленно Extern, Inline, MVA
Сортировка и фильтрация Сортировка –По комбинации атрибутов 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 K rows, MB, 4-5 M q/day Индексируем префиксы, а не сами слова Long query tail – top-N запросов в кэше на стороне приложения (20-30% из кэша, самый частый ~1-2%) 2 сервера с полными репликами индекса Loadavg (теперь) около
Пример 1.2. Просто поиск Boardreader.com 1B rows, 1.5 TB, 700K-1M q/day 6 серверов, 4xCPU + 16 GB RAM 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 доменов, на/с которых ссылались, и т.п Mrows, GB data, Kq –Запросы строго с группировкой и сортировкой по COUNT / COUNT DISTINCT –Много входных rows (1-10 M), при этом небольшой result set –Абсолютная точность не требуется MySQL исполнял прототипы до 300 секунд Распараллелили при помощи Sphinx
Пример 3. Группировка (contd) Группировка на 6x4 CPU кластере –Параллельно с другой нагрузкой –Распределенно, быстро, почти точно Предобработка индексируемых данных –UDF для выделения всех интересных подстрок в отдельные слова Потребовались доработки –COUNT DISTINCT –64-bit ids (из-за схемы нумерации и коллизий) Место для оптимизаций –Поскольку релевантность не важна…
Пример 4. MVA выборки Grouply.com N миллионов сообщений, M тегов Интересные применения для MVA Официальное для фильтрации по тегам Для экономии SQL выборок –БД сильно раздроблена на несколько физических серверов –JOIN в общем случае… нелегок –MVA для агрегации (в момент индексации), хранения, возврата ряда значений
Выводы Sphinx, понятно, не панацея Однако, для довольно широкого круга задач – неплохой выбор Кстати, ряд возможностей остался за бортом доклада… Пробуйте! Заходите – Пишите –