15 июня 2009 г. PHP Wordpress Windows SphinxSearch FreeBSD Поисковые системы

Sphinx. Установка, настройка и использование поискового движка

sphinx

Не так давно, я написал статью "FreeBSD. Установка и настройка Яндекс.Сервер" и пообещал в комментариях рассказать про поисковый движок Sphinx. Это одна из трех запланированных статей про этот замечательный поисковый движок, в следующих статьях расскажу про расширение для PHP и расширение для MySQL.

Операционная система, в которой будем производить установку и настройки - FreeBSD, но так же буду давать советы и для Windows-пользователей.

В качестве примера, будем разрабатывать поиск для моего блога на Wordpress. Для самых не терпеливых, вот демонстрация работы поисковика http://demo.adw0rd.ru/sphinxsearch/.

Установка

Установка достаточно простая

# cd /usr/ports/textproc/sphinxsearch
# make config

Выбираем:

  • "mysql", если вы пользуетесь данной СУБД и хотите работать с данными непосредственно из Sphinx
  • "iconv" для поддержки разных кодировок
# make install

Вот и все, установка завершена!

Скачать исходники и Windows-версии можно тут: http://sphinxsearch.com/downloads.html.

После скачки Windows-версии, достаточно распаковать архив и указать в системной переменной "Path" полный путь до каталога \sphinx\bin.

Настройка

До начала поиска надо проиндексировать вашу информацию, создадим наш конфигурационный файл и укажем что и как индексировать, а также как отдавать результаты поиска.

Создадим конфигурационный файл для нашего поиска по блогу /home/sphinx/sphinx.conf:

source adw0rd_wp
{
        # Параметры подключения к БД
        type = mysql
        sql_host = localhost
        sql_user = user
        sql_pass = password
        sql_db = database_name
        sql_port = 3306

        # Установим кодировку для работы с БД
        sql_query_pre = SET NAMES utf8
        sql_query_pre = SET CHARACTER SET utf8

        # Запрос выборки данных для индексации
        sql_query = SELECT ID as post_id, post_title, post_content FROM wp_posts WHERE post_type = 'post'

        # Запрос доп. информации для вывода результата (используется утилитой "search")
        sql_query_info = SELECT * FROM wp_posts WHERE ID = $id

        # Время простоя (sleep) перед посылкой запросов серверу (предназначен для разгрузки сервера БД)
        # Если установите "= 1000", то засыпание будет длится 1 секунду
        sql_ranged_throttle = 0
}

index adw0rd_wp
{
        # Использовать соответствующий source-блок настроек при индексации
        source = adw0rd_wp

        # Путь до файлов индекса
        path = /home/sphinx/data/adw0rd_wp

        # Способ хранения индекса (none, inline, extern)
        # Подробнее http://www.sphinxsearch.com/docs/manual-0.9.8.html#conf-docinfo
        docinfo = extern

        # Memory lock (http://www.sphinxsearch.com/docs/manual-0.9.8.html#conf-mlock)
        mlock = 0

        # Использование английского и русского стемминга
        morphology = stem_enru

        # Минимальная длина индексируемого слова
        min_word_len = 2

        # Установка используемой кодировки
        charset_type = utf-8

        # Таблица символов (http://www.sphinxsearch.com/docs/manual-0.9.8.html#conf-charset-table)
        charset_table = 0..9, A..Z->a..z, _, a..z, U+410..U+42F->U+430..U+44F, U+430..U+44F

        # Минимальная длина инфикса (префикс в том числе)
        min_infix_len = 2

        # Использовать оператор усечения "*" (http://www.sphinxsearch.com/docs/manual-0.9.8.html#conf-enable-star)
        enable_star = 1
}

indexer
{
        # Максимальный лимит используемой памяти RAM
        mem_limit = 32M
}

searchd
{
        # Адрес сервера
        address = 127.0.0.1

        # Порт
        port = 3312

        # Лог
        log = /home/sphinx/log/searchd.log

        # Лог запросов
        query_log = /home/sphinx/log/query.log

        # Таймаут на соединение с сервером (в секундах). При истечении времени происходит обрыв
        read_timeout = 5

        # Максимальное кол-во потомков от процесса
        max_children = 30

        # Путь до pid-файла
        pid_file = /home/sphinx/log/searchd.pid

        # Максимальное кол-во результатов выдачи
        max_matches = 1000
}
В новых версиях SphinxSearch надо использовать:
listen = 127.0.0.1:3312


Вместо
# Адрес сервера
address = 127.0.0.1

# Порт
port = 3312

Полная документация: http://www.sphinxsearch.com/docs/.

Разберем используемые нами SQL-запросы:

# Запрос выборки данных для индексации
sql_query = SELECT post_title, post_content FROM wp_posts WHERE post_type = 'post'

Тут мы выбираем заголовки и содержимое статей таблицы постов блога, при этом надо указать что типа поста - "post" (это та самая версия поста, которая считается опубликованной и текущей, так как есть еще ревизионные подверсии постов).


# Запрос доп. информации для вывода результата (используется утилитой "search")
sql_query_info = SELECT * FROM `wp_posts` WHERE `ID` = $id

Этот запрос применяется для вывода дополнительных данных результатов поиска используемый утилитой коммандной строки "search".

Индексация

Укажем в качестве конфига созданный нами конфигурационный файл:

# indexer --config /home/sphinx/sphinx.conf --all

Для обновления текущего индекса используйте "--rotate", он добавит к созданному индексу новые данные, а измененные соответственно изменит.

# indexer --config /home/sphinx/sphinx.conf --rotate

P.S. Если индексация не удалась, пишите комментарии к статье, посмотрим что случилось... :)

Использование поиска

Для поиска в консоли есть утилита "search":

# search --config /home/sphinx/sphinx.conf искомая комбинация

Запуск поискового сервера

Для работы с поисковым сервером, нам надо его запустить:

# searchd --config /home/sphinx/sphinx.conf

Далее, мы сможем использовать Sphinx API.

Использование Sphinx API для PHP

Для работы со Sphinx API необходимо подключить файл sphinxapi.php, вы можете найти эту библиотеку в поставке с дистрибутивом. Например для установки из портов FreeBSD - путь "/usr/ports/textproc/sphinxsearch/work/sphinx-0.9.8.1/api/sphinxapi.php", а для Windows - "sphinx\api\sphinxapi.php".

А теперь напишем скрипт для работы с проиндексируемыми данными поисковика, то есть для запросов искомых слов и вывода результатов поиска!

<html>
<head>
    <meta content="text/html; charset=utf-8" http-equiv="Content-Type"/>
    <title>Sphinx search for Wordpress</title>
</head>
<body>

<form action="" method="get">
    <input name="s" size="40" value="<?php echo @$_GET['s'];?>" />
    <input type="submit" value="Искать!" />
</form>
<?php

if(isset($_GET['s']) and strlen($_GET['s']) > 2) {

    // Подключаем sphinx-api
    require_once ("sphinxapi.php");

    // Искомая комбинация
    $string = $_GET['s'];

    // Создаем объект клиента для Sphinx API
    $sphinx = new SphinxClient();

    // Подсоединяемся к Sphinx-серверу
    $sphinx->SetServer('localhost', 3312);

    // Совпадение по любому слову
    $sphinx->SetMatchMode(SPH_MATCH_ANY);

    // Результаты сортировать по релевантности
    $sphinx->SetSortMode(SPH_SORT_RELEVANCE);

    // Задаем полям веса (для подсчета релевантности)
    $sphinx->SetFieldWeights(array ('post_title' => 20, 'post_content' => 10));

    // Результат по запросу (* - использование всех индексов)
    $result = $sphinx->Query($string, '*');

    // Если есть результаты поиска, то
    if ($result && isset($result['matches']))
    {

        // Соединяемся с БД
        mysql_connect('localhost', 'user', 'password');
        mysql_select_db('adw0rd_wp');

        // Устанавливаем кодировки
        mysql_query('SET NAMES utf8');
        mysql_query('SET CHARACTER SET utf8');

        // Получаем массив ID постов блога
        $ids = array_keys($result['matches']);

        // Выводим посты отсортированные по релевантности
        $id_list = implode(',', $ids);
        $sql = '
            SELECT `ID`, `post_title`, `post_content`
                FROM `wp_posts`
                WHERE `ID` IN ('.$id_list.')
                ORDER BY FIELD(`ID`, '.$id_list.')';

        $resource = mysql_query($sql);

        // Выводим результаты поиска
        echo '<ol>';
        while ($result = mysql_fetch_assoc($resource)) {
            echo '<li><span><a href="/?p='.$result['ID'].'">'.$result['post_title'].'</a></span><div>'.mb_substr(htmlspecialchars($result['post_content']), 0, 400).'</div>';
        }
        echo '</ol>';
    }
}
?>
</body>
</html>

Документация по Sphinx API для PHP: http://www.sphinxsearch.com/wiki/doku.php?id=php_api_docs

Резюме

За короткое время нам удалось развернуть быстрейший "поисковый сервис своими руками", с возможностями полнотекстового поиска. Демонстрация работы: http://demo.adw0rd.ru/sphinxsearch/.

По всем вопросам, касающемся этой статьи пишите в комментарии.

P.S. Если вам не знакомы слова: "стемминг", "инфикс", "словоформа" и т.д., то существует проект Википедия, в которой можно с легкостью об этом узнать!

Комментарии

ужас.... так то это, столько слов а на деле все за пару минут поднимается)) сфинкс акуенен

привет! пытаюсь поднять под windows xp. Так вот, я хочу попробывать поиск по базе, которая дается в качестве примера, где уже все настроенно. Там еще есть файл с SQL запросом, который создает таблицу documents и заполняет ее данными. Так вот при поиске через search я ввожу такую команду:

search test

а оно выдает:

using config file './sphinx.conf'...
index 'test1': search error: failed to open data/test1.sph: No such file or directory.

что это за файл? и почему test1, я же написал просто test?

А ты как индексировал? И какой у тебя путь до конфига получился?

Имхо намного пижже, чем Яндекс-сервер! Убедился на личном опыте)

А заказ на поднятие сфинкса для сайта возьмешь?

Zona, согласен, мне тоже больше нравится :)

aktuba, для какого сайта?
Свой сервер? Виртуальный?
Какой бюджет?

пиши на x11org@gmail.com

adw0rd: свои сервера, сайт nnm.ru =). Бюджет - хотелось бы у тебя услышать.

путь к конфигу у меня получился "c:\Program Files\sphinx\bin\sphinx.conf". И еще такой вопрос. Я пытаюсь выполнить индексацию. Делаю так:

C:\Program Files\sphinx\bin>indexer --all
Sphinx 0.9.8-release (r1533)
Copyright (c) 2001-2008, Andrew Aksyonoff
using config file './sphinx.conf'...
indexing index 'test1'...
collected 4 docs, 0.0 MB
sorted 0.0 Mhits, 100.0% done
total 4 docs, 193 bytes
total 0.152 sec, 1267.04 bytes/sec, 26.26 docs/sec
indexing index 'test1stemmed'...
FATAL: failed to open @CONFDIR@/data/test1stemmed.spl: No such file or directory, will not index. Try --rotate option.

в чем проблема? И как выставить @CONFDIR@ ? Где она прописывается?

aktuba, бюджет зависит от кол-ва данных и структуры поиска, я еще не могу представить это, без малейшего ТЗ. Но я заинтересован :)

А почему бы видео не записать как что делалось, небыло бы вопросов?

adw0rd: постучи в аську, plz: 255261508

У меня аськи нет :( http://adw0rd.ru/contacts

Если у тебя нет скайпа и жаббера, то могу в принципе восстановить аську

Есть скайп: aktuba. Есть и куча жабберов, но я ими не пользуюсь. Можешь добавить aktuba@qip.ru, но не обещаю, что контакт сохранится =)

aktuba, добавил тебя в скайпе и в жаббер :)

smackthat, укажи полный путь до каталога "/data/", там хранятся индексы. У меня в конфиге написано как это делать, ты читал внимательно?

шас еще раз прочту

smackthat, видео можно, сегодня попробую снять, но не обещаю :)
Может при следующих выпусках сниму...

разобрался, ищет через утилиту search. Вот осталось через php попробовать. А видео было б воопще клево!

Вот осталось через php попробовать.
ну попробуй по соей статье заюзать API :)

в общем попробывал, но страничка зависает, непойму почему. Делаю так:


    function search($search)
    {

    // Подключаем sphinx-api (я использую CodeIgniter)
     $this->load->library('sphinx');

     $this->sphinx->SetArrayResult(TRUE);
     $result = $this->sphinx->Query($search);

     return $result;        
    }  

Просто как будто загружается, но ничего не происходит, что это может быть?

также попробывал через обычный php, без фреймворка. Точно как у тебя в примере. таже ситуация - страничка подвисает. Проверил сервисы - SphinxSearch есть. Но при его ручном запуске выдает ошибку - Cant start service on local machine

теперь запустил через консоль сам демон и оно выдало такое:
This program (CLI search) is for testing and debugging purposes only;
it is NOT intended for production use.
C:\Program Files\sphinx\bin>searchd
Sphinx 0.9.8-release (r1533)
Copyright (c) 2001-2008, Andrew Aksyonoff
WARNING: forcing --console mode on Windows
using config file './sphinx.conf'...
creating server socket on 127.0.0.1:3312
accepting connections

// в этом месте была значительная пауза

caught SIGTERM, shutting down
shutdown complete

Дай полностью свой конфиг

#############################################################################
## data source definition
#############################################################################

source articles
{
        # Параметры подключения к БД
        type = mysql
        sql_host = localhost
        sql_user = root
        sql_pass = *********
        sql_db = testdatabase
        sql_port = 3306

        # Установим кодировку для работы с БД
        sql_query_pre = SET NAMES utf8
        sql_query_pre = SET CHARACTER SET utf8

        # Запрос выборки данных для индексации
        sql_query = SELECT id, title, category, description, key_words, short_text, id_author FROM articles

        # Запрос доп. информации для вывода результата (используется утилитой "search")
        sql_query_info = SELECT * FROM articles WHERE `id` = $id

        # Время простоя (sleep) перед посылкой запросов серверу (предназначен для разгрузки сервера БД)
        # Если установите "= 1000", то засыпание будет длится 1 секунду
        sql_ranged_throttle = 0
}



#############################################################################
## index definition
#############################################################################

index articles
{
        # Использовать соответствующий source-блок настроек при индексации
        source = articles

        # Путь до файлов индекса
        path = c:\Program Files\sphinx\bin\data\articles

        # Способ хранения индекса (none, inline, extern)
        # Подробнее http://www.sphinxsearch.com/docs/manual-0.9.8.html#conf-docinfo
        docinfo = extern

        # Memory lock (http://www.sphinxsearch.com/docs/manual-0.9.8.html#conf-mlock)
        mlock = 0

        # Использование английского и русского стемминга
        morphology = stem_enru

        # Минимальная длина индексируемого слова
        min_word_len = 2

        # Установка используемой кодировки
        charset_type = utf-8

        # Таблица символов (http://www.sphinxsearch.com/docs/manual-0.9.8.html#conf-charset-table)
        charset_table = 0..9, A..Z->a..z, _, a..z, U+410..U+42F->U+430..U+44F, U+430..U+44F

        # Минимальная длина инфикса (префикс в том числе)
        min_infix_len = 2

        # Использовать оператор усечения "*" (http://www.sphinxsearch.com/docs/manual-0.9.8.html#conf-enable-star)
        enable_star = 1
}

#############################################################################
## indexer settings
#############################################################################

indexer
{

    mem_limit           = 32M

}

#############################################################################
## searchd settings
#############################################################################

searchd
{
        # Адрес сервера
        address = 127.0.0.1

        # Порт
        port = 3312

        # Лог
        log = c:\Program Files\sphinx\log\searchd.log

        # Лог запросов
        query_log = c:\Program Files\sphinx\log\query.log

        # Таймаут на соединение с сервером (в секундах). При истечении времени происходит обрыв
        read_timeout = 5

        # Максимальное кол-во потомков от процесса
        max_children = 30

        # Путь до pid-файла
        pid_file = c:\Program Files\sphinx\log\searchd.pid

        # Максимальное кол-во результатов выдачи
        max_matches = 1000
}


# --eof--

а это нормально что порты не совпадают?
source articles
{
sql_port = 3306
}

searchd
{
port = 3312
}

smackthat, первый порт - SQL, второй - Sphinx

ясно. А в чем проблема не знаешь? В переменную Path добавил путь к папке bin, но не пашет.

В переменную Path добавил путь к папке bin, но не пашет.
Прописать патх нужно для вызова search, searchd, indexer, без прописывания полного пути...

Сейчас посмотрю конфиг...

>Прописать патх нужно для вызова search, searchd, indexer, без прописывания полного
>пути...
а вот оно что))) не силен я в этих консольных штуках...

>Сейчас посмотрю конфиг...
жду)))

smackthat, а ты создал каталог "c:\Program Files\sphinx\bin\data"?

да, и после индексации в нем появились файлы articles с разными форматами sp*

smackthat, проверял работу SQL-запросов? Я просто протестил с твоими конфигами, все нормально!

Ты так в точности запускаешь? Если нет, покажи как именно.


# indexer --config c:\Program Files\sphinx\sphinx.conf --all
# search –-config c:\Program Files\sphinx\sphinx.conf искомая комбинация
# searchd –-config c:\Program Files\sphinx\sphinx.conf

C:\Program Files\sphinx\bin>indexer --config "C:\Program Files\sphinx\sphinx.conf" --all
Sphinx 0.9.8-release (r1533)
Copyright (c) 2001-2008, Andrew Aksyonoff
using config file 'C:\Program Files\sphinx\sphinx.conf'...
indexing index 'articles'...
collected 8 docs, 0.0 MB
sorted 0.0 Mhits, 97.8% done
total 8 docs, 9135 bytes
total 0.949 sec, 9630.17 bytes/sec, 8.43 docs/sec

C:\Program Files\sphinx\bin>search --config "C:\Program Files\sphinx\sphinx.conf" qip
Sphinx 0.9.8-release (r1533)
Copyright (c) 2001-2008, Andrew Aksyonoff
using config file 'C:\Program Files\sphinx\sphinx.conf'...
index 'articles': query 'qip ': returned 1 matches of 1 total in 0.000 sec
displaying matches:
1. document=82, weight=3
        id=82
        title=21 QIPxyZ ????????? ???? ??? ??????
        category=35
        type=1
        language=1
        description=QIP ????????? ???? ????
        key_words=qip, icq, internet, ?????, ?????
        short_text=? ????????? ??? ??????? ?????? ?? ??????? Mblogi (?????????? ?? QIP, ? ??????? ?? ????????? ??????????? ??????? ????????????? QIP Infium).

и еще там текст, в общем ищет


C:\Program Files\sphinx\bin>searchd --config "c:\Program Files\sphinx\sphinx.conf"
Sphinx 0.9.8-release (r1533)
Copyright (c) 2001-2008, Andrew Aksyonoff
FATAL: malformed or unknown option near 'Ц-config'; use '-h' or '--help' to see available options.
C:\Program Files\sphinx\bin>

теперь другой результат, так как раньше конфиг был в папке bin. Что делать?

FATAL: malformed or unknown option near 'Ц-config';
Что за "Ц-config"? Чего там "Ц" делает?

теперь другой результат, так как раньше конфиг был в папке bin
А причем тут папка "bin"?

adw0rd, так держать! Еще один замечательный программерско-админский пост!

это просто случайно скопировал, считай что последней строки нет. А можно как-то деинсталировать сервис, а потом повторно установить?

smackthat,

searchd --config c:\Webserver\usr\sphinx\sphinx.conf --stop

Snowcore, спасибо! :)

при попытке остановить пишет что pid файл недоступен или нечитаем. Хотя я и создал каталог, в котором он должен быть. В чем проблема? Также создавал этот пид файл (просто новый пустой файл с этим названием) пишет, что невалидный пид файл. Где его брать? При попытке проинсталировать (--install) пишет что сервис уже запущен.

PID не надо создавать, у меня он вообще не создается. *.pid - это Файл, в который сохраняется PID-процесса.

Спасибо за статью и пояснения я разобрался!

Ура! :)

А что за ошибка при индексации - column '1' has no name ?
Ошибка из-за строки

sql_query = SELECT id as news_id, topic, date FROM news

работает только если выбираем одно поле as его новое имя, типа

sql_query = SELECT id as news_id FROM news

Почему же не обрабатывает нормальный запрос?

splash, покажите source полнстью

source adw0rd_wp
{
        type = mysql
        sql_host = localhost
        sql_user = user
        sql_pass = pass
        sql_db = _mpc
        sql_port = 3306
        sql_query_pre = SET NAMES utf8
        sql_query_pre = SET CHARACTER SET utf8
        sql_query = SELECT id as news_id, topic, date FROM news
        sql_query_info = SELECT * FROM news WHERE id = $id
        sql_ranged_throttle = 0
}

Какая версия sphinx и mysql у вас? Только точнее, пожалуйста.

sphinx-0.9.8.1-win32
mysql 5.1.31
база в utf8

Думаю проблема с Win-версией, я под Windows не устанавливал Sphinx.
Посмотрите http://sphinxsearch.com/forum/view.html?id=937

Это я уже видел, но не могу найти библиотеку libmysql.dll от mysql 5.0.xx отдельно от дистриба общего...

http://dev.mysql.com/get/Downloads/MySQL-5.0/mysql-noinstall-5.0.83-win32.zip/from/http://gd.tuwien.ac.at/db/mysql/ разве тут вы не нашли?

Слишком огромный архив выкачивать ради одной dll...
Библиотеку нашёл, через exe всё работает, но при запуске через php выполняются следующие строки


$string = $_POST['s'];// Искомая комбинация
$sphinx = new SphinxClient();// Создаем объект клиента для Sphinx API
$sphinx->SetServer('localhost', 3312);// Подсоединяемся к Sphinx-серверу
$sphinx->SetMatchMode(SPH_MATCH_ANY);// Совпадение по любому слову
$sphinx->SetSortMode(SPH_SORT_RELEVANCE);// Результаты сортировать по релевантности
$sphinx->SetFieldWeights(array ('NAME' => 20, 'DESC_FULL' => 10));
echo '1';
$result = $sphinx->Query($string, '*');
echo '2';

на последней строке повисает минуты на 2 и без каких-либо ошибок и сообщений завершает работу, '1' выводится, '2' - нет.
Может из-за той же библиотеки, подменяю libmysql.dll в папке mysql - ничего не меняется, может нужна php_mysql.dll от старой версии...

splash, у меня этот архив качается 2 минуты. Вот ваша библиотека: http://1dfile.ru/get/2c5b91fca2ce752759aea959c3c08d03/libmysql.dll

может нужна php_mysql.dll от старой версии...
Вряд ли.

Спасибо за ссылку, но у меня такая же dll.
В общем всё решилось, глючил searchd, повисал при запуске, хотя висело окно с надписью ожидаю подключений... перегрузил всё что можно - заработало.
И библиотека вообще не при чём, при поиске через php она не используется.

И библиотека вообще не при чём, при поиске через php она не используется.
mysql-php-api ее не юзает?

Так теперь у вас все работает?

Да, спасибо!
Дело осталось за тестированием...