Работа с realtime индексами (RT) в поисковом движке Sphinx
Кто не знает что такое Sphinx
Сфинк — это бесплатный полнотекстовый поисковый движок. С быстрой индексацией документов, стоп-словами, умеет интегрироваться с самыми известными БД Mysql, MsSql, Oracle и тд, также имеет АПИ с популярными языками программирования PHP, Perl, Java и тд. Также имеет поддержку SQL синтаксиса. Более подробнее тут.
Версии поисковика
На сегодня последняя версия 2.0.1, не смотрите что она бета, на этом проекте беты очень стабильны.
Также есть версия 1.10, из неё родилась версия выше, а эту отправили в утиль архив.
К стабильной версии относится 0.9.9
Я к сожалению не знаток всех этих версий в полной мере, и не могу что-то особо сильно утверждать, поэтому дам сугубо поверхностную оценку различий версий.
Начиная с версии 1.10 появились relatime индексы. Это индексы которые изменяются «на лету», т.е. не нужно делать промежуточные индексы и через какое-то время сливать их с главным индексом.
Во всех версия появилась возможность создавать таблицу в MySQL 5.x с движком SPHINX (Sphinx storage engine), т.е. появилась возможность обращаться к данным поискового индекса через SQL запросы к БД MySQl, более подробно тут
Также во всех версиях доступен API.
Более подробно обращайтесь к разным блогам, документации поисково движка.
Какие бывают индексы
Есть обычный индекс с ним неотъемлемо связан дельта индекс, который затем сливается с индексом (merge).
Чем мне этот тип индекса не понравился. Например, у вас есть БД с огромным кол-во записей (новостная система) и каждый день добавляется по 500-1000 новостей, вот тут необходимо производить множество операций, создавать описание главного индекса, также создавать описание вспомогательного индекса, который будет потом добавлять в главный индекс, т.е. небольшое кол-во данных которые пришли за указанное вами время. Затем необходимо запускать процедуру объединения дельта индекса и главного индекса. Получается ситуация, что добавили новость в БД, а она появится в поисковом индексе только когда произойдет объединение индексов, время конечно задаёт программер, но все таки это какой-то промежуток + плюс куча операций.
С версии 1.10 появились «realtime» (RT) индексы, они работают только с SphinxQL, т.е. заполнение данных в индекс, удаление, изменение происходит по средству SQL запросов (очень хорошо описано тут). Самая ВАЖНАЯ особенность этого типа индекса, то что данные попадают в тот же момент, когда они попадают в БД (вам нужно просто создать два запроса, один в БД, а другой в индекс Сфинкса). Этот индекс мне очень понравился и я его с успехом применил в одном проекте. Вот как с ним работать я бы и хотел поведать в этой статье.
Работа с RealTime Index
Лучше всего показывать на реальном примере, дабы сразу видеть результаты.
Создаем БД MySQL и в ней таблицу новостей
CREATE TABLE news ( id INT(11) NOT NULL AUTO_INCREMENT, date TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP, title VARCHAR(500) NULL DEFAULT NULL COLLATE 'utf8_unicode_ci', descr VARCHAR(2000) NULL DEFAULT NULL COLLATE 'utf8_unicode_ci', keywords VARCHAR(200) NULL DEFAULT NULL COLLATE 'utf8_unicode_ci', text VARCHAR(16000) NULL DEFAULT NULL COLLATE 'utf8_unicode_ci', `show` TINYINT(1) NOT NULL DEFAULT '0', PRIMARY KEY (id) ) COMMENT='Новости' COLLATE='utf8_unicode_ci' ENGINE=MyISAM AUTO_INCREMENT=1;
Далее создадим конфиг для поисковика для индекса новостей.
index rt_news { type = rt path = f:/sphinx/data/rt_news rt_field = title rt_attr_timestamp = date rt_field = descr rt_field = keywords rt_field = text rt_attr_uint = view rt_attr_string = title rt_attr_string = descr rt_attr_string = keywords rt_attr_string = text docinfo = extern morphology = stem_enru min_word_len = 1 html_strip = 1 charset_type = utf-8 enable_star = 1 rt_mem_limit = 256M } searchd { listen = 127.0.0.1:9306:mysql41 log = f:/sphinx/searchd.log query_log = f:/sphinx/query.log pid_file = f:/sphinx/searchd.pid read_timeout = 5 max_children = 30 max_matches = 1000 workers = threads # for RT to work }
В конфиге есть две обязательные секциии index нужна для описания индекса и searchd тут описываются настройки самого демона (службы) поисковика.
Разберем.
После названия секции index идет название индекса (произвольное [a-zA-Z0-9_] возможно есть еще знаки, но думаю этого достаточно для описания), далее идет описание самого индекса, указывается тип индекса, путь где будет хранится индекс, лучше пусть путь будет на латинице, т.к. используется кодировка UTF-8 и под виндой русское название будет в кракозябрах. Далее идет описание полей и их тип подробнее о различных типах тут, далее идут управляющие команды индексом, какую морфологию использовать, сколько памяти отводить, какая кодировка и тд, есть еще куча настроек, но она специфична и зависит уже от поставленных задач, обращайтесь к документации.
В секции searchd описываются команды для поисковика, какой порт слушать для обращения к MySQL, где хранятся разные лог-файлы и прочее.
Имея конфиг запустим поисковик, буду показывать все в командной строки для наглядности
F:\sphinx\bin>searchd.exe --config f:\Sphinx\sphinx.conf Sphinx 2.0.1-beta (r2792) Copyright (c) 2001-2011, Andrew Aksyonoff Copyright (c) 2008-2011, Sphinx Technologies Inc (http://sphinxsearch.com) using config file 'f:\Sphinx\sphinx.conf'... listening on 127.0.0.1:9306 precaching index 'rt_news' precached 1 indexes in 0.011 sec
Служба запущена и показывает что слушает Mysql на порту 9306 и создан один индекс с названием rt_news.
Добавление данных в БД и индекс
Пришло время заполнить БД и индекс данными. Подключаемя к поисковику через mysql на порту 9306
F:\Zend\MySQL 5.1.52\bin>mysql -P9306 Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 1 Server version: 2.0.1-beta (r2792) Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. This software comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to modify and redistribute it under the GPL v2 license Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql>
Запишем просто одну запись в БД (в примере только запрос, как его исполнять решать вам) и одну запись в поисковый индекс.
# В БД INSERT INTO `news` (`id`, `date`, `title`, `descr`, `keywords`, `text`, `show`) VALUES (1, '2011-09-17 12:02:49', 'Название новости', 'Описание новости', 'Ключевые слова', 'Текст новости ', 1);
# В поисковый индекс F:\Zend\MySQL 5.1.52\bin>mysql -P9306 Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 1 Server version: 2.0.1-beta (r2792) Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. This software comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to modify and redistribute it under the GPL v2 license Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql> INSERT INTO `rt_news` (`id`, `date`, `title`, `descr`, `keywords`, `text`, `view`) VALUES (1, '1316250169', 'Название новости', 'Описание новости', 'Ключевые слова', 'Текст новости ', 1); Query OK, 1 row affected (0.03 sec) mysql>
Обратите внимание, что вставлять в индекс надо с указанием primary key, по умолчанию это поле id, также необходимо указывать название индекса куда вставляются данные.
Теперь в БД и индексе есть данные, можно с ними работать.
Извлечение данных из индекса
mysql> SELECT * FROM rt_news WHERE view=1\G; *************************** 1. row *************************** id: 1 weight: 1 view: 1 date: 1316250169 title: Название новости descr: Описание новости keywords: Ключевые слова text: Текст новости 1 row in set (0.00 sec) # Параметр \G позволяет вывести данные вертикально
Изменение данных в БД и индексе
# Для БД UPDATE `news` SET `title`='Name of news' WHERE `id`=1 LIMIT 1;
# Для индекса mysql> REPLACE INTO `rt_news` (`id`, `date`, `title`, `descr`, `keywords`, `text`, `view`) VALUES (1, '1316250169', 'Name of news', 'Описание новости' , 'Ключевые слова', 'Текст новости ', 1); Query OK, 1 row affected (0.03 sec) # просмотр изменений для индекса mysql> SELECT * FROM rt_news WHERE view=1\G; *************************** 1. row *************************** id: 1 weight: 1 view: 1 date: 1316250169 title: Name of news descr: Описание новости keywords: Ключевые слова text: Текст новости 1 row in set (0.00 sec)
Удаление данных из БД и индекса
# Для БД DELETE FROM `news` WHERE `id`=1 LIMIT 1;
# Для индекса mysql> DELETE FROM `rt_news` WHERE id=1; Query OK, 0 rows affected (0.00 sec) # просмотр данных из индекса mysql> SELECT * FROM rt_news WHERE view=1\G; Empty set (0.01 sec)
Заключение
Как видно ничего сложного тут вообще нет, просто добавляется один запрос к работес данными и все, не надо создавать дельта индексы, мержить их и заниматься прочей трудоемкой работой.
Слышал мнение, что RT индексы сильно медленно работаю по сравнению с обычными индексами, но данная статья это опровергает.
Будут вопросы задавайте.
ЗЫ Еще один момент, все запросы которые относятся к БД я делал через обращение к mysql через порт 3306 (дефолтный), а запросы которые относятся к индексу через порт 9306, который указан в конфиге.
Статья просмотренна 727245 раз, зашло посетителей 76549