Sphinx, часть 1: Начало
Date December 11th, 2009 Author Vitaly Agapov
Sphinx – это отличный полнотекстовый поисковый движок, который легко интегрируется в любое web-приложение и не требует особых усилий по установке и настройке. Распространяется он по лицензии GPL2 и в настоящее время поддерживает СУБД MySQL и PostgreSQL, а также работу с XML-файлами. Название Sphinx принято расшифровывать как SQL Phrase Index, а автором его является наш соотечественник Андрей Аксёнов.
Но хватит на этом теории. Посмторим, как приручить этого мифического зверя…
Чтобы дать наиболее адекватную и проверенную информацию, в качестве примера я опишу процесс разработки поиска для одного из своих проектов. Сразу оговорюсь, что в примере будет использоваться ОС Linux (в моём случае – Ubuntu, но это непринципиально), СУБД MySQL и web-приложение на Perl.
Установка
Скачать дистрибутив можно здесь: http://sphinxsearch.com/downloads.html.
Кроме исходников для компиляции в unix здесь же можно скачать и версию для Windows. На момент написания статьи последней стабильной версией является Sphinx 0.9.9 от 2 декабря 2009 года.
Качаем дистрибутив и делаем привычные вещи:
1.
tar
-xzvf sphinx-0.9.8.
tar
.gz
2.
cd
sphinx
3.
./configure
4.
make
5.
make
install
Перед тем, как начинать компиляцию, есть смысл обратить внимание на возможные параметры скрипта configure (полный список – ./configure –help). Во-первых, по умолчанию Sphinx установится в директорию /usr/local, что не очень удобно. Поэтому лучше указывать путь –prefix=/usr/local/sphinx, что поможет избежать путаницы в файлах.
Во-вторых, если планируется использовать драйверы PostgreSQL, то надо явно указывать необходимость поддержки этих драйверов ключом –with-pgsql (драйверы MySQL компилируются по умолчанию).
Если скрипт configure ругается на отсутствие заголовков mysql-devel, то их надо доустановить. В Ubuntu надо поставить следующие пакеты:
1.
sudo
apt-get
install
libmysqld-dev libmysqlclient15-dev libmysql++-dev
После установки в директории /usr/local/sphinx/bin (или /usr/local/bin, если не использовался ключ –prefix) появятся следующие бинарники:
- indexer – утилита для создания индексов
- indextool – утилита для получения сводной информации об индексе
- search – тестовая утилита для проверки работы движка из командной строки
- searchd – демон, предоставляющий API для доступа к индексу внешним приложениям
- spelldump – утилита для кастомизации индекса с помощью словарей ispell или MySpell.
Установка завершена. Но до того, как можно будет пойти выпить пива, нужно еще выполнить несколько действий: сконфигурировать Sphinx, создать индекс, проверить его и, наконец, использовать Sphinx API в нашем web-приложении. Но прежде чем приступать к конфигурированию, посмотрим на нашу базу данных и определимся с тем, что мы хотим получить в качестве результата поиска.
База данных
В нашем примере у нас есть три таблицы:
book содержит информацию о книгах (название, аннотацию и год)
author содержит информацию об авторах (имя)
aob определяет их связь, то есть каждая её строка задаёт соответствие между первичными ключами из таблиц book и author
Нам требуется по введенному слову или словосочетанию находить как авторов, так и книги. При этом если в строке поиска ввести, например, фамилию автора и часть названия книги, то должна быть найдена соответствующая книга соответствующего автора и среди прочих найденных объектов должна находиться выше по релевантности.
Конфигурирование
Весь конфиг Sphinx находится в одном файле – sphinx.conf, располагающийся в /usr/local/sphinx/etc (или /usr/local/etc, опять же если не использовался ключ –prefix).
Вот конфиг для нашего случая:
001.
source
book
002.
{
003.
# Параметры подключения к БД
004.
type
= mysql
005.
sql_host = <host>
006.
sql_user = <mysql username>
007.
sql_pass = <mysql password>
008.
sql_db = <db name>
009.
sql_port = 3306
010.
011.
sql_query_pre = SET NAMES utf8
012.
sql_query_pre = SET character_set_results=utf8
013.
014.
sql_query = \
015.
SELECT book.
id
AS
id
, book.name AS name, book.year AS year, book.orig_name AS orig_name, \
016.
book.annotation AS annotation, GROUP_CONCAT(author.name) AS aname \
017.
FROM book LEFT JOIN aob ON book.
id
=aob.book_id \
018.
LEFT JOIN author ON aob.author_id=author.
id
GROUP BY book.
id
019.
sql_attr_uint = year
020.
021.
sql_ranged_throttle = 0
022.
023.
sql_query_info = SELECT * FROM book WHERE
id
=$
id
024.
}
025.
026.
source
author
027.
{
028.
type
= mysql
029.
sql_host = localhost
030.
sql_user = booklist
031.
sql_pass = Grecto84
032.
sql_db = booklist
033.
sql_port = 3306
# optional, default is 3306
034.
035.
sql_query_pre = SET NAMES utf8
036.
sql_query_pre = SET character_set_results=utf8
037.
038.
sql_query = \
039.
SELECT
id
, name, orig_name \
040.
FROM author
041.
042.
sql_ranged_throttle = 0
043.
sql_query_info = SELECT * FROM author WHERE
id
=$
id
044.
}
045.
index book_search
046.
{
047.
# использовать блок source book
048.
source
= book
049.
# путь, куда сохранять файл индекса
050.
path = /var/data/sphinx/book
051.
docinfo = extern
052.
mlock = 0
053.
054.
morphology = stem_enru
055.
min_word_len = 1
056.
057.
charset_type = utf-8
058.
# маппинг символов, например U+401 (Ё) и U+451 (ё) приравниваются к U+435 (е)
059.
charset_table = 0..9, A..Z->a..z, _, a..z, U+410..U+42F->U+430..U+44F, U+430..U+44F, U+401->U+435, U+451->U+435
060.
html_strip = 0
061.
062.
index author_search
063.
{
064.
source
= author
065.
path = /var/data/sphinx/author
066.
docinfo = extern
067.
mlock = 0
068.
069.
morphology = stem_enru
070.
min_word_len = 2
071.
072.
charset_type = utf-8
073.
charset_table = 0..9, A..Z->a..z, _, a..z, U+410..U+42F->U+430..U+44F, U+430..U+44F
074.
html_strip = 0
075.
}
076.
077.
indexer
078.
{
079.
mem_limit = 32M
080.
}
081.
searchd
082.
{
083.
listen = 3312
084.
log = /var/log/searchd.log
085.
query_log = /var/log/query.log
086.
087.
read_timeout = 5
088.
client_timeout = 300
089.
max_children = 30
090.
pid_file = /var/log/searchd.pid
091.
092.
max_matches = 1000
093.
seamless_rotate = 1
094.
preopen_indexes = 0
095.
unlink_old = 1
096.
mva_updates_pool = 1M
097.
max_packet_size = 8M
098.
max_filters = 256
099.
max_filter_values = 4096
100.
}
А теперь посмотрим в конфиг более пристально. Он состоит из нескольких блоков:
- source определяет параметры источника данных, то есть из каких таблиц и какие поля мы должны выбрать в индекс.
- index определяет параметры индексирования.
- indexer определяет глобальные параметры для работы утилиты indexer.
- searchd определяет параметры демона searchd
Блоков source и index может быть любое количество – в зависимости от наших потребностей. У нас этих блоков по паре: для индексации таблицы book и для индексации таблицы author.
Рассмотрим некоторые строки конфига подробнее.
С параметрами подключения к БД всё ясно. Дальше идут строки
1.
sql_query_pre = SET NAMES utf8
2.
sql_query_pre = SET character_set_results=utf8
Они определют запросы, которые будут выполнены сразу после подключения к БД перед началом индексации. В данном случае мы устанавливаем кодировку UTF8 для работы с базой данных.
Дальше идёт
1.
sql_query = \
2.
SELECT
book.id
AS
id, book.
name
AS
name
, book.
year
AS
year
, book.orig_name
AS
orig_name, \
3.
book.annotation
AS
annotation, GROUP_CONCAT(author.
name
)
AS
aname \
4.
FROM
book
LEFT
JOIN
aob
ON
book.id=aob.book_id \
5.
LEFT
JOIN
author
ON
aob.author_id=author.id
GROUP
BY
book.id
Это запрос для выборки данных для последующей индексации. Все поля, перечисленные в селекте, будут участвовать в полнотекстовом поиске.
Еще одно поле:
1.
sql_attr_uint = year
Задаёт нетекстовое поле для индексации. В данном случае это целочисленное значение. По нему мы впоследствии сможем добавлять условия для поиска. Sphinx также может работать и с другими типами данных атрибутов (опции sql_attr_bool, sql_attr_bigint, sql_attr_timestamp, sql_attr_str2ordinal, sql_attr_float)
1.
sql_ranged_throttle = 0
Это поле задаёт задержку в миллисекундах между индексируемыми порциями данных. В данном случае указан 0, что означает отсутствие задержки. Однако при больших размерах базы данных и нежелании подвешивать её на время индексации, есть смысл загружать и индексировать данные порциями. Для этого потребуется в sql_query добавить условие WHERE id>=$start AND id<=$end, а также прописать опцию sql_range_step = 1000, в которой укажем размер порции, загружаемой за один раз.
Дальше:
1.
sql_query_info =
SELECT
*
FROM
book
WHERE
id=$id
Это запрос, используемый утилитой search при вызове из командной строки. Утилита, находя в индексе подходящие строки, возвращает первичный ключ этой строки, а затем пользуется указанным здесь запросом для получения всех остальных полей строки. Вместо $id подставляется как раз найденный в индексе первичный ключ.
Индексация
Для того, чтобы проиндексировать базу данных, используем команду indexer:
1.
indexer --config /usr/
local
/etc/sphinx.conf --all
Можно вместо –all указать конкретный индекс. А если запущен searchd и на время индексации останавливать его нежелательно, то нужно добавить ключ –rotate:
1.
indexer --config /usr/
local
/etc/sphinx.conf -- rotate --all
Если ошибки не вылезли, то переходим к следующему шагу…
Тестирование индекса
Для поиска из командной строки используется утилита search:
1.
search --config /usr/
local
/etc/sphinx.conf <search_text>
Если выводимые результаты похожи на правду, то запускаем поисковый демон…
Запуск сервера searchd
Запускаем сервер командой
1.
searchd --config /usr/
local
/etc/sphinx.conf
Опять же, если нет ошибок, а ps waux | grep searchd показывает то, что надо, то радуемся – осалось совсем чуть-чуть.
Sphinx API для Perl
Об этом – статья «Sphinx, часть 2: Perl API»
Tags: Linux, MySQL, Perl, Sphinx
Category:
Linux, MySQL, Web-dev |
2 Comments »
22 September 2015 - 16:29
[…] прошлой статье «Sphinx: начало» я описал процедуру установки Sphinx и показал, как […]
22 September 2015 - 16:33
[…] Sphinx, часть 1: Начало […]