суббота, 28 октября 2017 г.

Поисковый движок SPHINX.

Поисковый движок SPHINX.

Установка движка в CentOS7

1. Скачиваем с сайта пакет RPM
http://sphinxsearch.com/downloads/release/
Я выбрал пакет RHEL/CentOS 7.x x86_64 RPM 2.2.11-release (6.2M)

2. Копируем пакет в папку /usr/src

3. В консоли переходим в папку с пакетом
# cd /usr/src/

4. Проводим установку sphinx
# yum install -y sphinx-2.2.11-1.rhel7.x86_64.rpm
Вместе с необходимым пакетом установятся так же postgresql-libs и  unixODBC

5. Конфигурационный файл службы - /etc/sphinx/sphinx.conf
Зарезервируем на всякий случай конфигурационный файл
# cp /etc/sphinx/sphinx.conf /etc/sphinx/sphinx.conf.default

Настройка сервиса sphinx для работы с базой MySQL и запуск сервиса

1. Для работы поиска с помощью sphinx сделаем тестовую базу данных MySQL, наполним ее тестовыми данными, проведем создание индекса:

Подключаемся к базе MySQL (MariaDB)
# mysql -u root –p
Создаем базу test
> CREATE DATABASE test;
Заливаем тестовые данные, которые присутствуют в /usr/share/doc/sphinx-2.2.11/example.sql 
> SOURCE /usr/share/doc/sphinx-2.2.11/example.sql;
Выходим из базы
> quit;
Тестовые данные представляют из себя таблицу с записями, содержащими текст. Упрощенно это записи:
( 1, 'test one', 'this is my test document number one. also checking search within phrases.' ),
( 2, 'test two', 'this is my test document number two' ),
( 3, 'another doc', 'this is another group' ),
( 4, 'doc number four', 'this is to test groups' )

2. Редактируем имеющийся конфигурационный файл. Он по умолчанию создан для работы с базой MySQL. Файл содержит несколько секции
source – раздел описывает источник данных
index – раздел описывает местоположение индекса и с каким источником будет работать индекс. Их может быть несколько. Один для испытаний я закомментировал
indexer – раздел описывает параметры работы с индексами
searchd – здесь описание демона sphinx
# nano /etc/sphinx/sphinx.conf
Содержимое тестового конфигурационного файла:
#
# Minimal Sphinx configuration sample (clean, simple, functional)
#

source src1
{
        type                    = mysql

        sql_host                = localhost
        sql_user                = root
        sql_pass                = **********
        sql_db                  = test
        sql_port                = 3306  
        sql_query               = \
           SELECT id, group_id, \
           UNIX_TIMESTAMP(date_added) AS date_added, \
           title, content \
           FROM documents

        sql_attr_uint           = group_id
        sql_attr_timestamp      = date_added
}


index test1
{
        source                  = src1
        path                    = /var/lib/sphinx/test1
}


indexer
{
        mem_limit               = 128M
}


searchd
{
        listen                  = 9312
        listen                  = 9306:mysql41
        log                     = /var/log/sphinx/searchd.log
        query_log               = /var/log/sphinx/query.log
        read_timeout            = 5
        max_children            = 30
        pid_file                = /var/run/sphinx/searchd.pid
        seamless_rotate         = 1
        preopen_indexes         = 1
        unlink_old              = 1
        workers                 = threads # for RT to work
        binlog_path             = /var/lib/sphinx/
}

3. Создадим индекс используя конфигурационный файл
# indexer –-all
Вывод будет следующий:
Sphinx 2.2.11-id64-release (95ae9a6)
Copyright (c) 2001-2016, Andrew Aksyonoff
Copyright (c) 2008-2016, Sphinx Technologies Inc (http://sphinxsearch.com)
using config file '/etc/sphinx/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.041 sec, 4682 bytes/sec, 97.04 docs/sec
total 4 reads, 0.000 sec, 0.1 kb/call avg, 0.0 msec/call avg
total 12 writes, 0.000 sec, 0.1 kb/call avg, 0.0 msec/call avg

4. Запуск демона sphinx
# systemctl start searchd
Добавление в автозагрузку
# systemctl enable searchd
Проверка статуса:
# systemctl status searchd

5. Подключиться к серверу sphinx используя клиент MySQL
# mysql -h0 -P9306
Получим приглашение
MySQL [(none)]>
Проверка поиска по тестовой базе. Найдем фразу 'test document'
MySQL [(none)]> SELECT * FROM test1 WHERE MATCH('test document');
+------+----------+------------+
| id   | group_id | date_added |
+------+----------+------------+
|    1 |        1 | 1507959119 |
|    2 |        1 | 1507959119 |
+------+----------+------------+
2 rows in set (0.00 sec)
Проверка поиска по ключевым словам в тестовой базе
MySQL [(none)]> CALL KEYWORDS ('test one three', 'test1', 1);
+------+-----------+------------+------+------+
| qpos | tokenized | normalized | docs | hits |
+------+-----------+------------+------+------+
| 1    | test      | test       | 3    | 5    |
| 2    | one       | one        | 1    | 2    |
| 3    | three     | three      | 0    | 0    |
+------+-----------+------------+------+------+
3 rows in set (0.00 sec)
Видно, что индекс построился правильно. Поиск работает. Обращаясь к сервису, мы можем получить ID записи в базе.

Настройка Sphinx для работы с источником данных xml

1. Для того, чтобы сервер успешно создал индекс, необходимо подготовить правильную структуру данных. Пример структуры данных разместим в /mnt/base.xml
<?xml version="1.0" encoding="utf-8"?>
<sphinx:docset xmlns:sphinx="http://sphinxsearch.com/">

  <sphinx:schema>
    <sphinx:field name="name" attr="string" />
  </sphinx:schema>

  <sphinx:document id="800">
    <name>
    ip address
    </name>
  </sphinx:document>

  <sphinx:document id="801">
    <name>MAC address</name>
  </sphinx:document>

  <sphinx:document id="802">
    <name>get post html</name>
  </sphinx:document>

  <sphinx:document id="803">
    <name>Мой документ</name>
  </sphinx:document>

</sphinx:docset>

2. Настройка конфигурации для парсинга xml документа будет такой:
# nano /etc/sphinx/sphinx.conf
Раздел source:
source basexml
{
    type                 = xmlpipe2
    xmlpipe_command      = /usr/bin/cat /mnt/base.xml
}
Главное здесь – это команда, которая будет читать данные и выводить в стандартный вывод linux. В нашем случае – это /usr/bin/cat /mnt/base.xml
Раздел index
index knowledgebase
{
    source       = knowledgebase
    path         = /var/lib/sphinx/knowledgebase
    # Минимальная длина слова
    min_word_len = 2
    min_prefix_len = 3
    html_strip = 1
    # Позволяет использовать звездочки в запросах, к примеру
    # по запросу *пр* будут найдены проспект, привет и пр.
    enable_star = 1
    # Автоматически расширяет поисковый запрос до трех запросов
    # running -> ( running | *running* | =running )
    expand_keywords = 1
    index_exact_words = 1
    morphology = stem_enru
}

3. Перезапуск процесса построения индексов выполняет так
# indexer --all --rotate
Sphinx 2.2.11-id64-release (95ae9a6)
Copyright (c) 2001-2016, Andrew Aksyonoff
Copyright (c) 2008-2016, Sphinx Technologies Inc (http://sphinxsearch.com)
using config file '/etc/sphinx/sphinx.conf'...
indexing index 'basexml'...
collected 3 docs, 0.0 MB
sorted 0.0 Mhits, 100.0% done
total 3 docs, 38 bytes
total 0.005 sec, 7165 bytes/sec, 565.71 docs/sec
indexing index 'test1'...
collected 4 docs, 0.0 MB
sorted 0.0 Mhits, 100.0% done
total 4 docs, 193 bytes
total 0.003 sec, 57134 bytes/sec, 1184.13 docs/sec
total 13 reads, 0.000 sec, 0.0 kb/call avg, 0.0 msec/call avg
total 24 writes, 0.000 sec, 0.0 kb/call avg, 0.0 msec/call avg
rotating indices: successfully sent SIGHUP to searchd (pid=2372).

4. Поиск по индексу basexml слова ‘post’ выполняется так же:
# mysql -h0 -P9306
MySQL [(none)]> SELECT * FROM basexml WHERE MATCH('post');
+------+---------------+
| id   | name          |
+------+---------------+
|  802 | get post html |
+------+---------------+
1 row in set (0.00 sec)

5. Для того что бы сделать периодическую ротацию индексов, в cron помещаем задание, которое будет выполняться к примеру дву раза в день:
/usr/bin/indexer --rotate --config /etc/sphinx/sphinx.conf --all > /dev/null

Использование PHP для работы с сервером Sphinx.

Для работы в PHP с сервером sphinx можно использовать два подхода:
1) Sphinx API 
2) SphinxQL
Будем использовать второй способ, как наиболее простой. Этот способ позволяет обращаться к серверу через клиент MySQL и работать с SQL подобным языком запросов. В PHP необходимо использовать PDO для подключения к серверу.
Пример кода:
$db = new PDO('mysql:host=127.0.0.1;port=9306;charset=utf8', '', '');
$q = "SELECT id FROM knowledgebase WHERE MATCH('".$what_sphinx."');";
$stmt = $db->query($q);
if($stmt->rowCount() > 0) {
   foreach ($stmt->fetchAll() as $row) {
        $arr_sphinx_rez[] = $row['id'];
   }
}
В переменной $what_sphinx можно писать просто слово, так и использовать выражения OR (|) или AND (&)