- PVSM.RU - https://www.pvsm.ru -
Более-менее большой проект рано или поздно приходит к необходимости полнотекстового поиска по контенту.
Для этой цели был придуман поисковый движок Sphinx [1].
Когда база становится большой либо индексов много переиндексация начинает занимать довольно длительное время, что может иметь разные негативные последствия для проекта. В этот момент стоит задуматься об использовании delta-индексов [2].
Автор столкнулся с этой необходимостью в тот момент, когда переиндексация начала занимать более часа.
Но это все подробно описано в документации и делается довольно просто:
source src_mysql
{
type = mysql
sql_host = localhost
sql_user = sphinx
sql_pass = secret
sql_range_step = 1000
}
source src_news : src_mysql
{
sql_db = project
sql_query_pre = SET NAMES utf8
sql_query_pre = SET CHARACTER SET utf8
sql_query_pre = REPLACE INTO sph_counter SELECT 'src_news', MAX(id) FROM news
sql_query_range = SELECT MIN(id), MAX(id) FROM news
sql_query = SELECT id as news_id, title, content FROM news WHERE id>=$start AND id<=$end
}
source src_news_delta : src_news
{
sql_query_pre = SET NAMES utf8
sql_query_pre = SET CHARACTER SET utf8
sql_query_range =
sql_query = SELECT id as news_id title, content FROM news
WHERE id > ( SELECT max_value FROM sph_counter WHERE source = 'src_news')
sql_query_post = REPLACE INTO sph_counter SELECT 'src_news', MAX(id) FROM news
}
Теперь рассмотрим случай когда индексирующих серверов несколько. Причин для этого может быть несколько, но появляется проблема: один сервер произведя индексацию переписывает в БД значение последнего ID. При запуске индексации на следующем сервере в выборку не попадут записи проиндексированные предыдущим сервером. Возникают «пробелы» в индексах и поисковая выдача будет постоянно разная, причем будут упущены случайные результаты.
Что делать?
Нужно в таблице sph_counter дополнительно хранить ID индексирующего сервера.
Добавляем колонку hostname.
В итоге таблица будет иметь следующий вид:
CREATE TABLE IF NOT EXISTS `sph_counter` (
`source` varchar(100) NOT NULL DEFAULT '',
`max_value` bigint(20) NOT NULL,
`hostname` varchar(50) NOT NULL DEFAULT '',
PRIMARY KEY (`source`,`hostname`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
* Обратите внимание на индекс, он необходим для корректной работы REPLACE INTO
Далее в зависимости от вашей конфигурации варианта 2:
В такой ситуации задача решается довольно просто: используем глобальную переменную MySQL — 'hostname'
Наша конфигурация приобретает следующий вид:
source src_news : src_mysql
{
sql_db = project
sql_query_pre = SET NAMES utf8
sql_query_pre = SET CHARACTER SET utf8
sql_query_pre = REPLACE INTO sph_counter SELECT 'src_news', MAX(id), @@hostname FROM news
sql_query_range = SELECT MIN(id), MAX(id) FROM news
sql_query = SELECT id as news_id, title, content FROM news WHERE id>=$start AND id<=$end
}
source src_news_delta : src_news
{
sql_query_pre = SET NAMES utf8
sql_query_pre = SET CHARACTER SET utf8
sql_query_range =
sql_query = SELECT id as news_id, title, content FROM news
WHERE id > ( SELECT max_value FROM sph_counter WHERE source = 'src_news' AND hostname = @@hostname)
sql_query_post = REPLACE INTO sph_counter SELECT 'src_news', MAX(id), @@hostname FROM news
}
В такой ситуации использовать глобальную переменную hostname уже не получится — мы будем всегда получать имя сервера, на котором работает БД.
Выход: будем использовать информацию о соединении и пользовательские переменные.
source src_news : src_mysql
{
sql_db = project
sql_query_pre = SET NAMES utf8
sql_query_pre = SET CHARACTER SET utf8
sql_query_pre = SELECT @sphinx_instance:=IF(STRCMP(@sphinx_host:=SUBSTRING_INDEX(host,':',1),'localhost'),@sphinx_host,@@hostname) AS sphinx_instance
FROM information_schema.processlist WHERE ID=connection_id();
sql_query_pre = REPLACE INTO sph_counter SELECT 'src_news', MAX(id), @sphinx_instance FROM news
sql_query_range = SELECT MIN(id), MAX(id) FROM news
sql_query = SELECT id as news_id, title, content FROM news WHERE id>=$start AND id<=$end
}
source src_news_delta : src_news
{
sql_query_pre = SET NAMES utf8
sql_query_pre = SET CHARACTER SET utf8
sql_query_pre = SELECT @sphinx_instance:=IF(STRCMP(@sphinx_host:=SUBSTRING_INDEX(host,':',1),'localhost'),@sphinx_host,@@hostname) AS sphinx_instance
FROM information_schema.processlist WHERE ID=connection_id();
sql_query_pre = REPLACE INTO sph_counter SELECT 'src_news', MAX(id), @sphinx_instance FROM news
sql_query_range =
sql_query = SELECT id as news_id, title, content FROM news
WHERE id > ( SELECT max_value FROM sph_counter WHERE source = 'src_news' AND hostname = @sphinx_instance)
sql_query_post = REPLACE INTO sph_counter SELECT 'src_news', MAX(id), @sphinx_instance FROM news
}
Эта конфигурация будет работать в обоих случаях.
Автор: darken99
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/mysql/10687
Ссылки в тексте:
[1] Sphinx: http://sphinxsearch.com/
[2] delta-индексов: http://sphinxsearch.com/docs/current.html#delta-updates
Нажмите здесь для печати.