Sphinx, часть 3. Real-Time индексы
Date November 8th, 2010 Author Vitaly Agapov
— Вот именно, — ответил проходящий мимо куст.
Минувшим летом команда Андрея Аксёнова осчастливила комьюнити новой версией Sphinx за нумером 1.10-beta. Среди прочих полезных нововведений вроде строковых атрибутов и многопоточного поиска была фича, название которой заставило моё сердце биться быстрей – RT-индексы. При более подробном изучении документации возбуждение поугасло, ибо ожидания мои, видимо, были сильно завышенными. Но тем не менее шаг вперёд сделан. И какой шаг! Это то, чего старому Сфинксу очень не хватало, отчего до сих пор в некоторых задачах приходилось пользоваться старым-добрым, но сильно тормознутым LIKE.
Итак, мы получили быстрый поиск по индексу, обновляющемуся в реальном режиме времени. Но кармические законы вселенной подсказывают, что необходимо при этом что-то и отдать и от чего-то отказаться. А отказаться придётся от префиксов и инфиксов (будем надеяться на будущие версии), от MVA-атрибутов (аналогично), а также подготовиться к тому, что индекс обновлять нам придется вручную. Последний пункт означает, что при добавлении записи в базу надо сделать INSERT в индекс, при удалении из базы – DELETE из индекса, а при изменении записи в таблице – REPLACE всё в тот же индекс. Неудобно, но за всё надо платить. Раньше в такой ситуации пришлось бы переиндексировать весь индекс целиком или хотя бы дельту.
Посмотрим более детально.
Создание RT-индекса
Лезем в конфиг sphinx.conf и добавляем новую секцию index:
index rt { type = rt path = /var/data/sphinx/rt rt_mem_limit = 1G rt_field = bname rt_field = aname rt_field = oname rt_field = altname docinfo = extern mlock = 0 min_word_len = 2 charset_type = utf-8 charset_table = 0..9, A..Z->a..z, _, a..z, U+410..U+42F->U+430..U+44F, U+430..U+44F html_strip = 0 }
Сюда же при необходимости можно добавить атрибуты, но можно не пытаться добавлять директивы min_infix_len, enable_star, source и иже с ними.
Дальше в секции searchd надо добавить директивы:
workers = threads listen = localhost:9306:mysql41
Если не будет первой, то при запуске searchd ругнётся:
WARNING: index ‘rt': RT index requires workers=threads – NOT SERVING
Если не будет второй, то до RT-индекса нельзя будет достучаться по протоколу MySQL. Пока что это, кстати, единственный протокол для работы с RT-индексами, но разработчики обещают реализовать в будущем и другие.
Перезапускаем sphinx, после чего можем немного поиграться:
$ mysql -h 127.0.0.1 -P 9306 Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 1 Server version: 1.10-dev (r2153) Type 'help;' or '\h' for help. Type '\c' to clear the buffer. mysql> INSERT INTO rt VALUES ( 1, 'first', 'test', 'test', 'test' );
mysql> SELECT * FROM rt WHERE MATCH('test'); +------+--------+ | id | weight | +------+--------+ | 1 | 1643 | +------+--------+
Заполнение индекса
Для начала нам потребуется создать индекс для уже имеющихся в базе данных. Это уже потом мы сможем манипулировать записями в этом индексе по мере изменения данных в рабочей БД. Задача вроде бы не сложная, так что я уже, закатав рукава, собирался было написать соответствующий скрипт, но вовремя погуглил и нашёл готовый инструмент, так что новый велосипед не понадобился.
Найти этот инструмент можно здесь. Это php-скрипт, создающий RT-индекс в соответствии с конфиг-файлом, очень напоминающим секцию source в файле sphinx.conf. В самом простом случае без использования дельта-индексов конфигурационный файл sources.ini может выглядеть так:
[source_for_rt_index] sql_host = localhost sql_user = <user> sql_pass = <pass> sql_db = <db_name> sql_port = 3306 sphinx_host = 127.0.0.1 sphinx_index = rt sphinx_port = 9306 sql_query_pre[] = SET NAMES utf8 sql_query = "SELECT book.id AS id, book.name AS bname, book.orig_name AS oname, book.alt_name AS altname, GROUP_CONCAT(author.name) AS aname FROM book LEFT JOIN aob ON book.id=aob.book_id LEFT JOIN author ON aob.author_id=author.id WHERE book.id>=$start and book.id<$end GROUP BY book.id" sql_query_range = "SELECT min(id) , MAX(id) FROM book" sql_range_step = 10000
После этого стартуем сам скрипт и радуемся жизни:
php indexer.php
Теоретически, если правильно организовать обновление индекса “на лету”, то этот скрипт более не понадобится. Но я для собственного спокойствия добавил его в cron для еженощного запуска – так всегда уверен, что индекс актуален, и в нем не накапливаются расхождения с боевой базой данных.
Связанные статьи
Ссылки
Tags: MySQL, Sphinx, Web-dev
Category:
MySQL, Web-dev |
3 Comments »
30 November 2012 - 12:25
Не могли бы вы пояснить зачем для rt_index указывать source. Вроде бы его фишка в том, что не надо указывать source и он будет игнорировать это.
30 November 2012 - 12:50
Не понял вопроса. В тексте чётко написано, что “можно не пытаться добавлять директивы min_infix_len, enable_star, source и иже с ними”.
То есть никакого source в конфигурации индекса нет.
В данном случае source мы задаём для отдельного скрипта, который позволит нам предварительно набить rt-индекс уже имеющимися значениями.
17 June 2015 - 22:51
Виталий, спасибо за ценный пост. Потратил кучу времени на RT и только у вас прочёл про этот скрипт. Буду пробовать.