Установка Sphinx под Linux - строим свой поисковый сервер
Sphinx - поисковый сервер и открытым исходным кодом (Open Source Search Server) для индексации контента из баз данных и осуществления полнотекстового поиска, разработанный Андреем Аксеновым. В статье пошагово рассказано как установить и настроить поисковый сервер Sphinx на сервер под управлением операционной системы Linux (Ubuntu/Dedian). Приведены примеры, советы и ссылки которые будут полезны как администраторам так и разработчикам.
Прежде чем приступить к пошаговому мануалу по установке и настройке поискового сервера Sphinx хочу вам рассказать как я познакомился с данной системой и что послужило толчком к ее использованию.
Содержание:
- Вступление
- Поиск от Яндекса и его минусы
- Поисковый движок Sphinx
- Как это работает
- Установка и настройка Sphinx на Linux
- Скрипт автозапуска searchd для init.d
- Скрипт автозапуска searchd для systemd
- Настройка автоматической переиндексации
- Защита служебных портов
- Пример взаимодействия со Sphinx на PHP
- Заключение
Вступление
С самого начала, когда только начинал программировать на PHP и писал несложные сайты, я использовал собственный самописный поисковый движок с простой логикой. Он воспринимал одно и несколько слов в поисковой фразе и выдавал те записи в которых было обнаружено вхождение. Сначала делал с индексированием контента и кешированием индекса, потом делал полнотекстовый поиск на PHP.
Конечно же данная реализация не лишена недостатков, основной недостаток - это не достаточно релевантная поисковая выдача поскольку мой движок не учитывал морфологию слов, а искал только прямые вхождения поисковых фраз с простым анализом распределенности по статье. Писать мощный поисковый модуль со сложной логикой и оптимизациями "на стероидах" у меня не было ни времени ни особого желания.
Поиск от Яндекса и его минусы
Позже я узнал про поиск от Яндекса, который без особого труда можно прикрутить к своему сайту используя Yandex XML Search API. К моему движку был написан модуль для осуществления поиска используя Yandex XML Search API и казалось бы все просто супер но со временем меня начали не устраивать некоторые ограничения и неудобства при работе с Yandex XML Search.
Вот что мне показалось неудобным при использовании Yandex XML Search API:
- ограничение на количество запросов в сутки, а потом еще сделали график ограничений для разного времени суток. Хотите уменьшить ограничения...отправьте СМС на номер...шутка, можно стать партнером Яндекса, для аккаунта зарегистрироваться в партнерской сети Яндекс Директ (РСЯ), связаться с поддержкой Яндекса и рассказать им зачем вам нужно большое количество запросов к Yandex XML Search API.
- поиск производится только по контенту, который проиндексирован Яндексом. Если странички нет в индексе Яндекса - ее вы никогда не увидите в поисковой выдаче своего сайта.
- привязка сайта к стороннему сервису, зависимость поиска от него.
Поисковый движок Sphinx
И тут я вспомнил что читал когда-то на Хабре и еще на каком-то блоге по HighLoad-проектам о мощном бесплатном поисковом движке с расширенным анализом и множеством возможностей по настройке и интеграции. Назывался этот движок Sphinx(сфинкс). Очень удачное название, хорошо запоминается и легко ищется в Google/Yandex.
Основные характеристики и возможности Sphinx:
- индексирование: до 10-15Мб на каждое ядро микропроцессора;
- поиск: 150-250 поисковых запросов в секунду на каждое ядро при 1Млн документов в индексе;
- высокая масштабируемость;
- распределенный поиск;
- поддержка до 32 и более полей при полнотекстовом поиске;
- поддержка дополнительный атрибутов для каждого из индексируемых документов;
- возможность использовать стоп слова;
- поддержка однобайтовых (СЗ1251 и т.п) и двухбайтовых кодировок (UTF-8);
- морфологический поиск с модулями для разных языков;
- поддержка MySQL и PostgreSQL из коробки;
- поддержка других ODBC совместимых баз данных;
- кроссплатформенность;
- готовые к использованию решения API для языков PHP, Python, Java.
Сфинкс используется на многих высоконагруженных проектах, к примеру это Хабрахабр, Викимапия и другие. Система себя зарекомендовала с наилучшей стороны, известно что существует поисковый кластер в котором проиндексировано около 3 миллиардов документов и который осуществляет более 50 миллионов поисковых запросов в сутки.
Полистав документацию и прочитав бегло несколько русских/английских статей по установке в уме быстро очертил себе четкий алгоритм действий. Со своим опытом установки и настройки Sphinx я хочу сейчас познакомить тебя, мой дорогой читатель.
Как это работает
На сервер ставится поисковый демон Sphinx, который индексирует через заданный промежуток времени статьи и контент вашего сайта - создает поисковый индекс.
На вашем сайте подключается Sphinx API, который есть для Java, PHP, Ruby (можно написать реализацию и для других языков), пишется поисковый модуль который делает несложные запросы к демону(сервису) Sphinx - searchd.
При запросе поисковой фразы с поисковой формы сайта через Sphinx API делается обращение к демону searchd, который нам возвращает ID записей с нужной сортировкой и фильтрацией. Дальше имея ID публикаций мы делаем один запрос к БД сайта и получаем всю информацию о наших статьях, остается только красиво вывести список найденных элементов.
Установка и настройка Sphinx на Linux
Предполагается что у вас уже установлена ОС Linux, на которой будет работать (или уже работает ) сайт или сервис, на котором нужно будет использовать Sphinx Search API.
Обновляем источники пакетов и ставим нужный софт:
apt-get update
apt-get install gcc make libmysqlclient15-dev libmysql++-dev g++
Идем по ссылке http://sphinxsearch.com/downloads/release/ и качаем архив с исходными кодами для последнего стабильного релиза ( Get Source tarball tar.gz ). Потом распаковываем архив и переходим в разархивированную папку. Вот к примеру я качал 2.1.3-release:
cd /tmp/
wget -c "http://sphinxsearch.com/files/sphinx-2.1.3-release.tar.gz" && ls
tar -xf sphinx-2.1.3-release.tar.gz
cd sphinx-2.1.3-release
Теперь компилируем наш Сфинкс с поддержкой MySQL (есть поддержка и других БД, смотри док.), поскольку весь полезный контент сайта хранится в БД MySQL:
./configure --with-mysql --prefix=/usr/local/sphinx
make
make install
Копируем шаблон файла с настройками и редактируем его содержимое под наши нужды:
cp /usr/local/sphinx/etc/sphinx.conf.dist /usr/local/sphinx/etc/sphinx.conf
nano /usr/local/sphinx/etc/sphinx.conf
В конфигурационном файле достаточно много настроек и все они заключены в секции где для каждого источника индексируемых данных описываются свои специфические опции и данные для доступа.
Приводить полное описание всех настроек я не буду, в шаблонном файле все хорошо документировано, а также в официальной документации (смотри ссылки в конце статьи) все понятно изложено. Чтобы все изначально прояснить приведу здесь текст своего конфигурационного файла с подробными комментариями:
# Настройки источника "mysqlbasename" с которого будем брать контент
source mysqlbasename
{
type = mysql # тип источника, в данном случае БД MySQL
sql_host = localhost # Хост MySQL
sql_user = dbusername # Пользователь MySQL
sql_pass = dbuserpassword # Пароль MySQL
sql_db = mysqlbasename # Название БД в MySQL
sql_port = 3306 # Порт сервера MySQL
sql_query_pre = SET NAMES CP1251 # Кодировка индексируемой таблицы
# Запрос которым делаем выборку всех записей, которые должны быть проиндексированы
sql_query = SELECT title, full_text FROM posts WHERE publicated=1
# Используется только в CLI (при обращении через командную строку), можно оставить пустым
sql_query_info = SELECT * FROM posts WHERE id=$id
}
# настройки построения индекса с использованием источника "mysqlbasename"
index mysqlbasename
{
source = mysqlbasename # Имя источника данных
# Путь по которому будут сохранены файлы индекса, если индекс большой то можно
# перенести на отдельный раздел или жесткий диск.
path = /usr/local/sphinx/var/data/mysqlbasename
# Настройка хранения значений атрибутов документов, extern - хранить раздельно по ID.
docinfo = extern
mlock = 0 # Бдокировка памяти для кеширования данных, 0 - нет.
morphology = stem_en, stem_ru, soundex # набор морфологическиз препроцессоров для обработки.
min_word_len = 3 # минисмальная длина слова для индексации
charset_type = sbcs # Single Byte Character Set - кодировка, в данном случае для CP1251.
html_strip = 1 # Чистить или нет HTML (1 - да)
}
# настройки индексатора
indexer
{
mem_limit = 32M # лимит памяти для работы индексатора
}
# настройки поискового демона (SearchDaemon, searchD)
searchd
{
listen = 9312 # порт для работы через API
listen = 9306:mysql41 # порт для комуникаций с MySQL
log = /usr/local/sphinx/var/log/searchd.log # логи демона
query_log = /usr/local/sphinx/var/log/query.log # логи поисковых запросов
read_timeout = 5 # таймаут чтения в секундах
client_timeout = 300 # таймаут поддержания соединения, между запросами в секундах
max_children = 30 # Максимально допустимое количество порождаемых процессов
pid_file = /usr/local/sphinx/var/log/searchd.pid # PID(ProcessID) файл родительского процесса
max_matches = 1000 # Максимальное количество полученных результатов
seamless_rotate = 1 # предотвращает паралич search при работе с большим количеством кешируемых данных
preopen_indexes = 0 # Откривать все индексы при запуске, 0 - нет
unlink_old = 1 # чистка старых индексов, 1 - да
mva_updates_pool = 1M # Резервируемый размер пула в ОЗУ для обновлений
max_packet_size = 8M # Максимальный размер сетевого пакета для обмена данными
max_filters = 256 # Максимальное количество фильтров что можно использовать на один запрос
max_filter_values = 4096 # Макс. количество значений для одного фильтра
}
# --eof--
Запускаем индексацию наших данных:
/usr/local/sphinx/bin/indexer --all --verbose
В случае успешного индексирования получим примерно вот такие строки:
Sphinx 2.1.3-dev (r4319)
Copyright (c) 2001-2013, Andrew Aksyonoff
Copyright (c) 2008-2013, Sphinx Technologies Inc (http://sphinxsearch.com)
using config file '/usr/local/sphinx/etc/sphinx.conf'...
indexing index 'mysqlbasename'...
WARNING: Attribute count is 0: switching to none docinfo
collected 518 docs, 3.2 MB
sorted 0.4 Mhits, 100.0% done
total 518 docs, 3195655 bytes
total 0.637 sec, 5013995 bytes/sec, 812.74 docs/sec
total 2 reads, 0.000 sec, 745.7 kb/call avg, 0.3 msec/call avg
total 8 writes, 0.001 sec, 390.4 kb/call avg, 0.2 msec/call avg
Запускаем поискового демона:
/usr/local/sphinx/bin/searchd
В случае успешного запуска должны увидеть примерно вот такой вывод:
Sphinx 2.1.3-dev (r4319)
Copyright (c) 2001-2013, Andrew Aksyonoff
Copyright (c) 2008-2013, Sphinx Technologies Inc (http://sphinxsearch.com)
using config file '/usr/local/sphinx/etc/sphinx.conf'...
listening on all interfaces, port=9312
listening on all interfaces, port=9306
precaching index 'mysqlbasename'
precached 1 indexes in 0.000 sec
Делаем тестовый поисковый запрос, где YOUR_QUERY_STRING - ваша поисковая фраза:
/usr/local/sphinx/bin/search --config /usr/local/sphinx/etc/sphinx.conf YOUR_QUERY_STRING
После запуска будет выведена длинная простыня записей что отвечают критериям поиска.
Проверяем работу поиска с использованием PHP API. Внимание: PHP должен быть установлен на сервере! "YOUR_QUERY_STRING" - ваш поисковый запрос
cd /tmp/sphinx-2.1.3-release/api/
php test.php YOUR_QUERY_STRING
Надеюсь у вас все получилось.
Скрипт автозапуска searchd для init.d
Теперь нужно сделать так чтобы демон searchd стартовал при загрузке/перезагрузке операционной системы. Ниже приведен пример создания и настройки скрипта для Debian/Ubuntu GNU/Linux без использования systemd.
Откроем для редактирования новый скрипт инициализации в папке "/etc/init.d":
nano /etc/init.d/searchd
Копируем и вставляем следующий текст (CTRL+C, CTRL+V) в скрипт /etc/init.d/searchd :
#!/bin/bash
#!/bin/sh
### BEGIN INIT INFO
# Provides: searchd
# Required-Start: $all
# Required-Stop: $all
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# X-Interactive: true
# Short-Description: Stop/Start SphinxSearch Daemon
### END INIT INFO
case "${1:-''}" in
'start')
/usr/local/sphinx/bin/searchd
;;
'stop')
/usr/local/sphinx/bin/searchd --stop
;;
'restart')
/usr/local/sphinx/bin/searchd --stop
sleep 1
/usr/local/sphinx/bin/searchd
;;
*)
echo "Usage: $SELF start|stop|restart"
exit 1
;;
esac
Установим права на скрипт запуска и зарегистрируем его в автозапуске:
chmod +x /etc/init.d/searchd
update-rc.d searchd defaults
Для надежности можете перезагрузить свой сервер и проверить запустился ли демон searchd:
reboot
ps ax | grep searchd
Скрипт автозапуска searchd для systemd
В более новых версиях GNU/Linux уже присутствует такой мощный набор управления системой как systemd. Чтобы добавить наш демон searchd в автозапуск системы с использованием systemd нужно проделать несколько несложных операций.
Откроем для редактирования новый файл будущего скрипта для управления запуском searchd:
nano /usr/local/sbin/systemd-searchd.sh
Копируем в редактор следующий текст скрипта:
#!/bin/sh
# Sphinx init script for searchd daemon.
case $1 in
start)
/usr/local/sphinx/bin/searchd
echo "Sphinx searchd started."
;;
stop)
/usr/local/sphinx/bin/searchd --stop
echo "Sphinx searchd stoped."
;;
restart)
/usr/local/sphinx/bin/searchd --stop
sleep 1
/usr/local/sphinx/bin/searchd
echo "Sphinx searchd restart complete."
;;
*)
echo "Usage: systemctl {start|stop|restart} searchd.service"
exit 1
esac
exit 0
Устанавливаем права на запуск скрипта:
chmod +x /usr/local/sbin/systemd-searchd.sh
Создаем конфигурационный файл для нашее службы (демона):
nano /etc/systemd/system/searchd.service
Копируем в редактор следующее содержимое:
[Unit]
Description=Sphinx searchd daemon
After=network.target
[Service]
Type=oneshot
ExecStart=/usr/local/sbin/systemd-searchd.sh start
ExecStop=/usr/local/sbin/systemd-searchd.sh stop
ExecReload=/usr/local/sbin/systemd-searchd.sh restart
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
Все должно работать!
Настройка автоматической переиндексации
Добавляем в системный планировщик заданий (крон, crontab) запуск индексатора через каждые сутки:
nano /etc/crontab
Добавляем в конец содержимого файла следующую строчку:
0 0 * * * root /usr/local/sphinx/bin/indexer --rotate --all --config /usr/local/sphinx/etc/sphinx.conf
Все готово! Вы установили и настроили поисковый сервер .
Защита служебных портов
После настройки и запуска поискового сервера Sphinx важно помнить что его демн открывает порты 9312, 9306 (указанные в настройках) и делает их доступными на всех интерфейсах. Настоятельно рекомендую закрыть их от внешнего мира при помощи файрвола на внешнем интерфейсе (интернет). Вот два простых правила для IPTABLES:
iptables -A INPUT -p tcp -i eth0 --dport 9306 -j DROP
iptables -A INPUT -p tcp -i eth0 --dport 9312 -j DROP
Где eth0 - имя сетевого интерфейса, который смотрит в интернет.
Пример взаимодействия со Sphinx на PHP
Итак, сервер настроен все проиндексировано, работоспособность проверена. Качаем себе Sphinx API класс для работы в PHP:
https://code.google.com/p/sphinxsearch/source/browse/trunk/api/sphinxapi.php?r=2014
Помещаем скрипт sphinxapi.php в свой проект и подключаем этот скрипт при помощи include/require.
Вот простая реализация подключения и выборки при помощи PHP(код для примера):
$cl = new SphinxClient();
$page = 3; // our results page number
$items_per_page = 10; // show 10 results per page
$index_name = 'mysqlbasename '; // Index name to fetch from
$request = 'купить носки';
$cl->SetServer( "localhost", 9312 ); // server, port
$cl->SetConnectTimeout( 1 ); // max connect timeout
$cl->SetMaxQueryTime(1000); // max query timeout
$cl->SetMatchMode( SPH_MATCH_ALL ); // ALL, ANY, PHRASE, EXTENDED...
$cl->SetLimits(intval($page*$items_per_page), intval($items_per_page), 1000);
$result = $cl->Query( $request, $index_name );
if ( $result === false ) {
if( $cl->GetLastWarning() ) { // check for warnings
echo 'WARNING: '.$cl->GetLastWarning();
exit;
}
// no warnings found, result=FALSE
exit('Cannot connect etc.');
}
echo 'Total results found: '.$result['total'];
// Compose comma separated string with posts IDs
foreach ($result['matches'] AS $key => $row)
$ids_arr[] = intval($key);
$ids_csv = join(',', $ids_arr);
// fetch posts from DB
$mysql_result = mysql_query(SELECT id, title, text FROM `posts` WHERE id IN (".$ids_csv.") AND publicated=1);
while ( $mysql_object = mysql_fetch_object($mysql_result) ) {
...
}
...
Заключение
Ниже привожу полезные ссылки по поисковому серверу Sphinx. Этой информации с лихвой достаточно чтобы во всем разобраться и настроить под себя.
Полезные ссылки:
- http://sphinxsearch.com - официальный сайт.
- http://sphinxsearch.com/docs/ - документация.
- http://sphinxsearch.com/wiki/doku.php?id=sphinx_docs - Wiki документация по Sphinx на одной странице.
- http://sphinxsearch.com/wiki/doku.php?id=php_api_docs - Wiki документация по PHP API для Sphinx.
UPD: последняя версия Sphinx с открытым исходным кодом - 2.3.2-beta. В последующих версиях код автором теперь не предоставляется, есть только готовые сборки с бинарными файлами.
Рекомендую обратить свое внимание на проект Manticore Search, который базируется на форке последней Open Source версии движка Sphinx и имеет множество улучшений и фич!
Доброго времени суток, Total results found показывает что 24, $result['matches'] отсутствует в массиве $result. Как проблему побороть?
Здравствуйте. Статья писалась на момент выхода версии sphinx-2.1.3-release, с этой версией все проверено и прекрасно работает. Если же у вас установлена данная версия то следует пересмотреть настройки сервера Sphinx, проверить все ли хорошо с кодировкой для вашего текста и с кодировкой по умолчанию для версии PHP, которая работает на вашем сервере приложений.
Если у вас другая, более свежая версия сервера SphinxSearch (например 2.2.10-release) то здесь нужно использовать более новый SphinxSearch PHP API - https://code.google.com/p/sphinxsearch/source/browse/trunk/api/sphinxapi.php
Также в данном случае более целесообразно использовать новый инструмент для запросов к серверу SphinxQL Query Builder for PHP, который является более производительным и позволяет задавать условия выборки результатов используя синтаксис подобный до языка SQL - http://sphinxsearch.com/blog/2014/10/20/sphinxql-query-builder-for-php/
добрый день,
я бы заказал у вас установку на сервер сфинкса.
бд с 3 млн товаров.
ответьте, если есть желание.
Статья немножко переработана, добавлено содержание с навигацией, а также пример создания скрипта автозапуска службы searchd под systemd для GNU/Linux.
На счет - Скрипт автозапуска searchd для systemd
Всего то нужно включить юнит в автозапуск
Debian 8.x Jessie - Sphinx 2.2.11
Верно, в новых версиях Sphinx все что нужно для автозапуска уже идет в комплекте если устанавливать поисковый движок из пакетов (*.deb к примеру). При сборке Сфинкса из исходных кодов, скрипты автозапуска придется настраивать вручную.