Главная > Теория и практика > Дельта индекс в Sphinx

Дельта индекс в Sphinx

sphinx

Spinx отлично зарекомендовал себя, как движок полнотекстового поиска. Он обладает отличными показателями производительности и вместе с этим является функционально мощным инструментом. Sphinx прекрасно справляется с большими объемами данных при поиске.

Но есть и другая, более медленная операция, с которой приходится сталкиваться - построение индекса. На малых объемах обычно используют перестройку всего индекса, которая занимает не много времени. В случае же большого количества данных индексирование может стать очень медленным процессом (время полной переиндексации в некторых системах достигает дней и недель). В этом случае результаты поиска будут обладать малой временной актуальностью.

Одним из решений подобной проблемы является использование дельта индекса, о чем мы поговорим в этой статье.

Схема дельта индексов

Схема очень примитивна. Вместо одного индекса, Вы сторите два:

  • основной, индексирующий все данные
  • дополнительный (или дельта), индексирующий только новые данные, появившиеся со времени последнего реиндексирования

Понятно, что дельта индекс будет работать гораздо быстрее. Следовательно, этот индекс и будет обновляться достаточно часто, чтобы Ваши поисковые данные были в актуальном состоянии.

Схема такого индекса называется main+delta. Рассмотрим на примере:

Данные

Пусть у нас есть таблица с очень простой структурой:

CREATE TABLE  `test`.`articles` (
  `id` int(10) unsigned NOT NULL auto_increment,
  `text` text,
  PRIMARY KEY  (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8

Ее и будем индексировать. Для начала ее нужно заполнить данными. Можно воспользоваться вот этим скриптом:

mysql_connect('localhost', 'root', 'root');
mysql_select_db('test');

$text = "Название XVII века, дано по Кисловской слободе. Кислошниками называли людей, профессионально занимавшихся засолкой и квашением овощей и ягод, приготовлением кислых напитков — кваса, щей и др. В районе нынешних Кисловских переулков находилась принадлежавшая двору царицы царицына Кисловская слобода.";

$words = explode(' ', $text);
mysql_query('set names utf8');

for ( $i = 1; $i < 10000; $i ++ )
{
	shuffle($words);
	mysql_query('INSERT INTO articles SET `text` = \'' . mysql_real_escape_string(implode(' ', $words)) . "'");
	echo '.';
}

Этот скрипт добавит 10000 рядков со случайным набором слов.

Основной индекс

При перестройке основного индекса, нам понадобиться знать ID последней проиндексированной статьи, для этого создадим еще одну таблицу в MySQL:

CREATE TABLE sph_counter
(
    counter_id INTEGER PRIMARY KEY NOT NULL,
    max_doc_id INTEGER NOT NULL
);

Теперь в конфигурационном файле (spinx.conf) обьявим параметры основного индекса:

source main
{
	# ... - тут идет тип и параметры доступа в СУБД

	sql_query_pre		= SET NAMES utf8
	sql_query_pre 		= REPLACE INTO sph_counter SELECT 1, MAX(id) FROM articles
	sql_query		= SELECT id, text FROM articles
	sql_query_info		= SELECT * FROM articles WHERE id=$id
}

index main
{
	source			= main
	path			= /var/data/articles.main
}

В таблицу sph_counter будет записываться ID последней проиндексированной статьи (в основном индексе). Этот индекс следует запускать редко (все зависит от времени реиндексации, но обычно основной индекс перестраивают ночью, в минимумы нагрузки).

Дельта индекс

Для построения дельта индекса будем использовать данные из таблицы sph_counter, что-бы узнать, начиная с какой записи строить индекс. Конфигурация будет следующая:

source delta : main
{
	sql_query_pre = SET NAMES utf8
	sql_query = \
		SELECT id, text FROM articles \
		WHERE id > ( SELECT max_doc_id FROM sph_counter WHERE counter_id=1 )
}

index delta : main
{
    source = delta
    path = /var/data/articles.delta
}

Как видно из конфигурации мы добавили дополнительный индекс. Запрос на выборку данных составлен начиная с последнего проиндексированного документа из основного индекса.

Поиск

Теперь пересторим главный и дельта индекс, а также запустим демон поиска:

indexer --all
searchd

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

...
$cl->Query ( "век", "main delta" );

После этого, можно добавить несколько рядков в таблицу и перестроить только дельта индекс:

indexer --rotate delta

Новый запрос поиска сразу отразит актуальное состояние таблицы. Т.к. дельта индекс работает очень быстро, следует перестраивать его довольно часто (раз в 5…15 минут). Основной индекс можно также не перестраивать, а сливать с дельта индексом (merge), но об этом в другой раз.

А Вы пользуетесь дельта индексами?

Google Bookmarks Digg I.ua Ru-marks Ruspace Zakladok.net Reddit delicious Technorati Yahoo My Web News2.ru БобрДобр.ru Memori.ru rucity.com

Статьи по теме

  1. Алексей
    25 Июнь 2009 в 04:53 | #1

    Я использую дельта индексы
    Правда в качестве “пометки” записываю в БД не ID последний записи, а дату последний индексации.

    На самом деле интересно было бы почитать о сливание. С этим возникли проблемы…

  2. 25 Июнь 2009 в 21:34 | #3

    Да, отличная статья, спасибо! Одно время, когда я участвовал в стартапе, там был нужен полнотекстовый поиск, сначала остановились на сфинксе, но так как у нас была критичной именно новая информация, при этом она создавалась и, что важно, редактировалась постоянно, пришлось отказаться и перейти на Xapian, там есть live-update index

  3. 30 Июнь 2009 в 20:32 | #4

    @aleks_raiden
    Интересно, спасибо!
    Что можете сказать о Xapian? Как он себя зарекомендовал?

  4. 3 Июль 2009 в 10:44 | #5

    @Den Golotyuk

    Сильно долго с ним заниматься не вышло, но по небольшому опыту - достаточно хорошо, много настроек и быстр, есть расширение к РНР, а также РНР-апи, хотя жуткая документация. к тому же сложности с win32 версией, потому разрабатывать и тестировать на win32 получается с некоторыми сложностями. А сам поиск и работа с ним мне понравилась, встроенный стеммер и нечеткий поиск, живое обновление индекса, распределенность и т.п.

  5. VojToshik
    4 Январь 2010 в 23:47 | #6

    Я боюся, що технологія індексації не буде працювати для випадку, коли статтю додали, потім її проіндексували (id статті вже менше значення каунтера в таблиці sph_counter). Потім статтю відредагувала, а в індексі буде старе значення навіть після дельта-переіндексації. Правильно?

  6. 5 Январь 2010 в 10:43 | #7

    @VojToshik
    Да, для этого необходимо периодически делать либо полную переиндексацию, либо использовать сливание индексов (во втором случае можно решить проблему обновлений проще и эффективнее - читать тут: http://highload.com.ua/index.php/2009/11/30/sphinxsearch-index-merging/).

  7. Mikhail
    10 Август 2010 в 13:52 | #8

    а почему не использовать sql_query_post_index вместо sql_query_pre, при определении ИД последнего проиндексированного документа.

  8. Mikhail
    10 Август 2010 в 15:17 | #10

    @Den Golotyuk
    ну я к тому чтобы несколько раз не индексировать одно и тоже при больших объемах информации.. ведь если ИД определим до начала индексации и начнем операцию, а кто-то добавит новые записи в процессе, то получим некоторые элементы одинаковыми и в индексе и в дельта индексе.

    это я в теории.. сам не сталкивался))

  9. 10 Август 2010 в 15:30 | #11

    @Mikhail
    Спасибо!
    То, что несколько документов может попасть в дельта-индкес дважды не страшно, т.к. их количество будет намного меньше полного дельта-индекса в любом случае.
    Кстати, в случае использования sql_query_post_index мы эти документы потеряем, т.к. в конце учтем и те документы, которые были добавлены во время индексации (но не были проиндексированы). Поэтому, всетаки, sql_query_post_index тут не подойдет.

  10. Mikhail
    10 Август 2010 в 15:55 | #12

    @Den Golotyuk
    а если использовать $maxid в sql_query_post_index запросе?

  11. 10 Август 2010 в 16:01 | #13

    @Mikhail
    Да, отличный вариант :)

  12. Mikhail
    10 Август 2010 в 16:17 | #14

    @Den Golotyuk
    ок, спасибо :)

  13. Евгений
    10 Февраль 2011 в 16:43 | #15

    Спасибо, отличная статья и отличный сайт)

  1. Пока что нет уведомлений.