Sphinx - настоящее быстрого поиска
Linux, Программирование 09.04.2008
Интро
В наше время трудно представить хороший сайт без функции поиска. При чем не просто поиска, а с поддержкой морфологии. В большинстве случаев хватит поддержки русского и английского языка.
И вот при разработке очередного проекта стала проблема поиска. Таблицы в базе не маленькие (от 100 000 записей), да плюс искать еще нужно сразу по нескольким, так что вариант с обычным LIKE ‘%запрос%’ отпал сам собой.
Ранее я пользовался поисковым движком mnoGoSearch, но вспомнив корявость его API (иногда скаладывалось впечатление, что его писали индусы с 5-ю классами приходской школы) отбросил и этот вариант.
В итоге, осталось 2 варианта:
- написать поиск по основе построения своих индексов и хранить эти индексы, например, в BerkleyDB;
- не изобретать велосипед и воспользоваться одним из самых быстрых поисковых движков - Sphinx.
Я выбрал второй вариант :)
К слову, Sphinx - это проект нашего соотечественника Андрея Аксенова. Стоит заметить, что у Андрея хватает сил и времени не только постоянно улучшать проект, но и активно учавствовать в поддержке пользователей, опреативно отвечая на вопросы на англоязычном и русскоязычном форуме. За что ему огромное спасибо!
Установка
И так, приступим к практике. Установка стандартна и не вызывает никаких проблем.
Скачиваем архив с исходниками (последняя версия на момент написания статьи), распаковываем и устанавливаем:
# ./configure
# make
# make install (под root)
Под FreeBSD выполнив эти 3 команды я получил продукт готовый к работе. А вот в Debian пришлось еще минуту повозиться (правда, в первый раз это заняло полчаса :) и выполнить:
# sudo aptitude install libmysql++-dev libmysqlclient15-dev checkinstall
после этого все прекрасно заработало.
Подготовка
Теперь все готово для создания индекса (я предполагаю, что у вас есть некий проект с готовой БД) . Наша база имеет следующую структуру:

Будем искать по названию продукта, его описанию и тегам. Таким образом нам нужно создать индекс по этим полям. Для этого создадим 2 каталога /home/larin/data/ - тут будем хранить файлы индекса и /home/larin/log/ - тут логи и конфигурационный файл /home/larin/sphinx.conf
sphinx.conf
source product
{
type = mysql
sql_host = localhost
sql_user = test
sql_pass = ******
sql_db = product
sql_port = 3306
sql_query_pre = SET NAMES cp1251
sql_query_pre = SET CHARACTER SET cp1251
sql_query = SELECT p.product_id, p.producе_title, p.product_description, t.tag_name FROM `product` p LEFT JOIN `product_tag` pt ON pt.product_id = p.product_id LEFT JOIN `tag` t ON pt.tag_id = t.tag_id
sql_query_info = SELECT * FROM `product` WHERE `product_id` = $id
sql_ranged_throttle = 0
}
index product
{
source = product
path = /home/larin/data/product
docinfo = extern
mlock = 0
morphology = stem_enru
min_word_len = 2
charset_type = sbcs
charset_table = 0..9, A..Z->a..z, _, a..z, U+A8->U+B8, U+B8, U+C0..U+DF->U+E0..U+FF, U+E0..U+FF
min_infix_len = 2
enable_star = 1
}
indexer
{
mem_limit = 32M
}
searchd
{
address = 127.0.0.1
port = 3312
log = /home/larin/log/searchd.log
query_log = /home/larin/log/query.log
read_timeout = 5
max_children = 30
pid_file = /home/larin/log/searchd.pid
max_matches = 1000
}
Вот и вся конфигурация, Sphinx готов начать индексировать ваши данные с гигантской скоростью :) Для более полной информации по конфигурированию зайдите на официальный сайт в раздел документации. Она на английском языке, но трудностей вызвать не должна, написана просто и доступно.
Морфология
Spninx поддерживает индексацию (а следовательно и поиск) с учетом морфологии русского и английского языка. Поддержка морфологии реализована при помощи стемминга.
Стемминг – это процесс ведущий к выделению основы слова из сложных словоформ.
Вот строки в конфиге отвечающие за конфигурацию:
#подключение русского и английского стемминга
morphology = stem_enru
#задание таблицы символов, данная настройка для Windows-1251
charset_type = sbcs
charset_table = 0..9, A..Z->a..z, _, a..z, U+A8->U+B8, U+B8, U+C0..U+DF->U+E0..U+FF, U+E0..U+FF
#важно отметить, что в Sphinx прификсы считаются частью инфикса, т.е. указав индексацию по инфиксам мы автоматически индексируем и по префиксам
min_infix_len = 2
#так должно быть :) Почему? Читайте документацию ;)
enable_star = 1
Индексация
Запускаем создание индекса:
# indexer –config /home/larin/sphinx.conf –all
Все, индекс создан! Давайте искать!
Поиск
Для отладки и проверки работоспособности индекса подойдет утилита search. Пример использования:
# search –config /home/larin/sphinx.conf искомая фраза
А вот для реальной работы, нужно запустить демон сфинкса - searchd:
# searchd –config /home/larin/sphinx.conf
Все, демон успешно стартовал (кстати, не плохо было бы добавить его в автозагрузку :) , и теперь мы с ним можем работать из наших PHP-скриптов, через официальное API. Необходимая библиотека sphinxapi.php находится внутри скачанного архива к каталоге api.
Пример скрипта
<?php
require ( "sphinxapi.php" );
//....
$string = @$_GET['string'];
$sphinx = new SphinxClient();
$sphinx->SetServer('localhost', 3312);
//Совпадение любого из слов
$sphinx->SetMatchMode(SPH_MATCH_ANY);
//Результаты отсортированы по релевантности
$sphinx->SetSortMode(SPH_SORT_RELEVANCE);
//Задаем полям веса, для подсчета релевантности
$w = array ('product_title' => 20, 'product_description' => 10, 'tag_name' => 5);
$sphinx->SetFieldWeights($w);
$result = $sphinx->Query($string, '*');
if ($result && is_array($result['matches']))
{
//Получаем массив ID найденых товаров
$ids = array_keys($result['matches']);
//А теперь выводим эти товары отсортированные по релевантности
$id_list = implode(',', $ids);
$sql = sprintf('SELECT * FROM `product` WHERE `product_id` IN (%s) ORDER BY FIELD(`product_id`, %s)', $id_list, $id_list);
//Все далее выполняем этот запрос и наслаждаемся результатами
}
//....
?>
Итого
Вот и все. И мы в очередной раз (как и в случае с UML и кэшированием) убедились, что все гениальное просто :)







Ай яй яй, 2008й год на дворе, а таблички или страница ещё не в utf8?
Хм.. видимо у вас сервак ой как далеко от Европы, раз часовой пояс такой
Артем, а в чем плюс UTF? Чем эта таблица лучше cp1251?
UTF лучше и лучше на эту тему не спорить ;)
Кстати, с Lucene если Sphinx сравнить, как он? Мы пользуем у себя именно Lucene.
А чем лучше? Все же хочется конкретики. Я спорить не буду - просто хочу услышать пару доводов )
Если сравнивать по скорости, то Sphinx значительно быстрее.
И кстати, у меня Lucene отказался искать по русским текстам. Поискал на форумах - все говорят проблемы у него с русским, а у вас нормально?
Вот, например, цитата с сайта Артёма Курапова:
Ага. Занятно. Надо будет его попробовать.
По поводу русского не знаю. Проект англоязычный, но проблем быть не должно: UTF он вроде воспринимает.
Так. Про плюсы UTF:
1. Многоязычность.
2. Спецсимволы вроде стрелочек.
3. Нет проблем с XMLHttpRequest.
Есть и ещё, но сходу так и не вспомню: последний раз с 1251 работал очень давно.
Занятные плюсы, правда мне многоязычность не нужна :) Со спец символами тоже проблем нет, а с AJAX ни разу не було проблем - сначала пользовался библиотекой Димы Котерова, теперь jQuery
А как MySQL работает с UTF8? В поле varchar(255) строку какой длины я смогу записать? 255 символов?
Да.
UTF это многоязычие. Сначала все проекты так говорят что всё только на одном языке.. Разрастаются, все каталоги, статьи, контакты в такой кодировке, а потом возникают всякие мелочи с другими языками - имена пользователей что-бы поддерживали всякие ÕÜÖÄ тоже.. Потом что-бы почта когда рассылается, не корёжилась от этих символов, потом что-бы где-нибудь в админке в таблице была “правильная” сортировка.. Вот и получается что программеры делают мелкие хаки, ставят ХТМЛ-коды для этих спец символов, потом сортируют данные вручную в обход БД. А когда таблиц уже эдак 100 и общий размер перевалил 10 гигов, то никому этим заниматься уж никак не хочется.
Sphinx не умеет дополнять индекс, требуется полная перестройка.
А xapian не пробовали? В нем тоде русский
Кто вам такое сказал? Прочтите внимательнее документацию - он все умеет =)
Спасибо за пост - познавательно!
ЗЫ: В последнем коменте очепятка ПроЧтите :)
@proft
Спасибо!
@kmmbvnr
И еще пара вопросов:
1) Как у xapian с русской морфологией?
2) И какой стемминг он использует для русского и английского языка?
3) Можно ли использовать сразу два стеммера?
Все эти вопросы возникли из-за плохой документации на сайте xapian.
Спасибо за пост, я как раз планировал использовать этот SE для одного проекта, а тут ты еще и мануал своевременно запостил :)
*ворчит* А я сразу говорил UTF8 упрощщает жизнь!
Да, глупости все это, на большинстве проектов UTF на фик не нужен
таки к сожалению нет. в документации следующее
там есть так называемый дельта индекс, но мне вот непонятно, а что если поиск не тупой влоб, а параметризованный, а параметры изменились именно в основной части таблицы - тогда увы и ах… пересобирать его заново.
хотя, если немного пошаманить, можно найти выход и из этой ситуации. задержки можно минимизировать.
Спасибо за статью. Позновательно.
а UTF8 - однозначно! 2008 год! :)
Для опций нужен двойной дефис:
indexer ––config /home/larin/sphinx.conf ––all
а понял, это так Wordpress режет
ring0, я поправил в твоем комменте дефисы, теперь все ОК. “ndash” нам поможет =)
Сорри, все сделал как было описано и на англ пошел поиск на ура, а на русском вообсче не ищет.
Выдает: Notice: Undefined index: matches in /bhome/part3/03/avenirru/avenir.ru/www/test.php on line 37
Уменя 37 строка это: if ($result && is_array($result['matches']))
т.е. получается массив не существует так как ничего не находит(((
кто нить сталкивался с трудностями поиска на русском?
вот еще заметил
при индексации при тех настройках что описаны вые выводится: indexing index ‘news’…
ERROR: index ‘news’: sql_query_pre[0]: Unknown system variable ‘NAMES’ (DSN=mysql://avenir_ru:***@baze.avenir.ru:64000/avenir_ru).
total 0 docs, 0 bytes
total 0.051 sec, 0.00 bytes/sec, 0.00 docs/sec
Говорит что не понимает строчку: sql_query_pre = SET NAMES cp1251
Что может быть???
Какая версия MySQL?
С версией разобрался поставил 5 и эта ошибка пропала. Но поиск на русском не идет, ток англ
вот мой конф, помогите поправить что не так(таблицы и БД в utf8):
source news
{
type = mysql
sql_host = mysql.baze.avenir.ru
sql_user = avenir_ru
sql_pass = ******
sql_db = avenir_ru
sql_port = 64547
sql_query_pre = SET CHARACTER_SET_RESULTS=utf8
sql_query_pre = SET NAMES utf8
sql_query_pre = SET CHARACTER SET utf8
sql_query = SELECT n.news_id, n.title, n.body FROM `news` n
sql_query_info = SELECT * FROM `news` WHERE `news_id` = $id
sql_ranged_throttle = 0
}
index news
{
source = news
path = /bhome/part3/03/avenirru/sphinx/sphinks/var/data/news
docinfo = extern
mlock = 0
morphology = stem_ru, stem_en
min_word_len = 2
charset_type = utf-8
charset_table = 0..9, A..Z->a..z, _, a..z, U+A8->U+B8, U+B8, U+C0..U+DF->U+E0..U+FF, U+E0..U+FF
min_infix_len = 2
enable_star = 1
}
index
{
mem_limit = 32M
}
searchd
{
address = 127.0.0.1
port = 3312
log = /bhome/part3/03/avenirru/sphinx/sphinks/var/searchd.log
query_log = /bhome/part3/03/avenirru/sphinx/sphinks/var/query.log
read_timeout = 5
max_children = 30
pid_file = /bhome/part3/03/avenirru/sphinx/sphinks/var/searchd.pid
max_matches = 1000
}
//А теперь выводим эти товары отсортированные по релевантности$id_list = implode(',', $ids);
$sql = sprintf('SELECT * FROM `product` WHERE `product_id` IN (%s) ORDER BY FIELD(`product_id`, %s)', $id_list, $id_list);
//Все далее выполняем этот запрос и наслаждаемся результатами
а этот запрос выполняем каким методом сфинкса???
Этот запрос выполняется вашим классом работы с БД, ну или попросту функцией mysql_query() )))
))) спасибо, вот только тогда не очень понятно а в чем прирост скорости? Если получается выполняется аж 2 запроса. Первый сам сфинкс в своих индексах, а потом еще и мы в БД?
Простите за глупые вопросы.)))
Прирост в том, что Sphinx в отличии от MySQL ищет записи в своем индексе с гигантской скоростью и по всем полям.
А мы выполняем всего один запрос (тот что с IN) который выполняется очень быстро, т.к. поиск идет по первичному ключу в таблице. Где вы увидели 2 запроса???
При индексации? Так этот процесс запускается много реже, по сравнению с обращениями к поиску. У меня на некоторых сайтах переиндексация запускается всего раз в сутки )
Pol_uha, что еще не понятно?
А если ВСЕ нужные мне поля в таблице были проиндексированы, почему сфинкс просто сразу не берет их оттуда и не выводит, а приходится еще делать запрос в БД?
Спасибо вам огромное, блог супер!!! Читаю другие статьи.)))
В Sphinx храниться индекс по данным, а не сами данные. Понимаете разницу?
Рад, что блог нравится и помогает )
Понимаю)))
А можете помоч в такой задачке:
Есть таблица с названиями животных и с id городов в которых они находятся)))
Проиндексированы соответственно 2 таблица: эта и с городами.
Человек ввел черепаха москва или черепахи в москве и т.д.
как мне сделать взаимодействие этих 2-х таблиц? Т.е. Находятся все черепахи и проверяются id городов в которых они живут и сравниваются с id из таблицы городов откуда берутся названия и сравниваются со 2-м словом, в данном случае “Москва”?
ПЛЗ!!!))))
И так, есть 2 таблицы:
town [town_id, town_title] и
animal [animal_id, animal_title, town_id]
Соответственно, для правильного создания индекса надо их объединить. Т.к. искать мы будем животных то первичным ключом в результатах запроса у нас будет animal_id.
Получим:
sql_query = SELECT animal_id, animal_title, town_title FROM `animal` a LEFT JOIN `town` t ON a.town_id = t.town_id
Все ))) Теперь индекс будет построен верно: поиск будет вестись по названию города и по названию зверушки.
З.Ы. LEFT JOIN сделан для случая когда не у всех зверушек задан город обитания.
Привет))) Ссори еще раз. А не подскажешь, как в сфинксе сделать абсолютный поиск. Т.е. при вводе “черный гиппопотам”
он не выдавал все записи где написано “черный” и “гиппопотам” отдельно, а только где есть фраза целиком?
Привет!
$sphinx->SetMatchMode(SPH_MATCH_ALL);
З.Ы. А вообще бывает полезно читать официальную документацию )))
Проблема аналогичная - не ищет по русски. Скрипт из примера ругается
Notice: Undefined index: matches in /usr/local/www/tomsk.fm/data/sphinx.php on line 45Данные в базе и страничка с тестовым скриптом в utf-8
Евгений, а у тебя чего то типа такого при индексации не возникает
indexing index ‘news’…
ERROR: index ‘news’: sql_query_pre[0]: Unknown system variable ‘NAMES’ (DSN=mysql://avenir_ru:***@baze.avenir.ru:64000/avenir_ru).
total 0 docs, 0 bytes
total 0.051 sec, 0.00 bytes/sec, 0.00 docs/sec
вообще проверь что мускуль от 4.1
Инкрементальный поиск поддерживается или нет? можно подробно об этом написать?
Ею можно управлять? например добавилось 15 страниц, как их добавить в индекс?
Какая нагрузка на сервер, при создании индекса например в электронном магазине, товаров 20 тыс. по времени? ориентировочно.
Еще бы в пример добавить метод BuildExcerpts для формирования сниппетов и новичкам будет ваще шоколадно.
[...] уже писал поисковом движке Sphinx:Sphinx - настоящее быстрого поиска и использовании его в [...]
Абсолютный Минимум, который Каждый Разработчик Программного Обеспечения Обязательно Должен Знать о Unicode и Наборах Символов
Автор, а вы на комментарии вообще отвечаете? или нет?
@Руслан Дворковой
Руслан, простите, из-за больших потоков спама, иногда не замечаю реальных людей )
Поддерживается. Это подробно описано в документации. Там все просто и разобраться можно даже без знания английского.
Этого вам не скажет никто. Все зависит от запросов. Сам Sphinx почти не создает нагрузки. Самая большая нагрузка создается при индексации и полностью зависит от сложности и “тяжести” запросов.
Для облегчения жизни сервера, индексировать можно итерационно, по 50-100 записей за заход. Пример, подраздел Ranged queries
Все, если остались вопросы - пишите.
Спасибо большое за ответы, реально порадовали они
Всем привет, спасибо за статью все классно , у меня проблема такая … если ищу так “nord холодильники” отлично работает, ищем так “nord холодильник” тоже все гуд,
ищем так “холодильники nord” все хорошо , а вот если так “холодильник nord” то все не чего не находит :( может кто знает что с этим делать ? заранее спасиб :)
Ребята извините разобрался спасибо ! просто звёзды убрал из $cl->Query(”*$search*”, “*”); от так $cl->Query(”$search”, “*”); все заработало ! :) спасибо
Elvis,
и Вам спасибо! Сами спросили, сами - ответили! =)
А, если нужно искать независимо по каждой сущности или вместе, как тогда делать?
Например, есть три таблицы: клиенты, машины, договора.
Искать нужно договора, например, по серии, ФИО клиента (из другой таблицы) и номеру ТС (из третьей таблицы).
Нужно искать клиентов. И нужно искать ТС (например по номеру и ФИО владельца из другой таблицы).
Как это сделать? Нужно использовать три индекса? Или один индекс стремя источниками?
Да, плюс к тому, если используется SphinxQL.
@А.Н.
Три различных индекса, по отдельности - будете искать по какому-либо одному индексу, и вместе - по всем )
Так получается, что нужен ещё один индекс по ТС и клиентам, вместе взятым?
Сколько же тогда времени займёт их создание? :-(
Знаете, очень тяжело разговаривать не видя проблемы перед глазами ) Скорее всего надо сесть и вечерок подумать… посмотреть на проблему с иной стороны.
А если же создание индексов занимает существенное время то стоит строить delta-индексы. А полный индекс перестраивать, например, раз в день или неделю.
Проблема в том, что у меня уже нет недели. :-)
Я сейчас столько думать не могу. Мне уже надо было сделать (месяц как).
Сейчас делаю поиск.
Вся проблема в том, что обычный MySQL поиск очень медленно работает.
Запрос получается вида следующего:
“select dogovor.ID_DOGOVOR as CNT_ID_DOGOVOR, dogovor.DOG_SER as CNT_DOG_SER, dogovor.DOGNUMB as CNT_DOGNUMB, dogovor.DATE_DOG_CREATE as CNT_DATE_DOG_CREATE, dogovor.DATE_DOG_INPUT as CNT_DATE_DOG_INPUT, dogovor.DATE_START as CNT_DATE_START, dogovor.DATE_END as CNT_DATE_END, dogovor.START_USE as CNT_START_USE, dogovor.END_USE as CNT_END_USE, dogovor.START_USE1 as CNT_START_USE1, dogovor.END_USE1 as CNT_END_USE1, dogovor.START_USE2 as CNT_START_USE2, dogovor.END_USE2 as CNT_END_USE2, dogovor.ZNAK_SER as CNT_ZNAK_SER, dogovor.ZNAK_NO as CNT_ZNAK_NO, dogovor.COMMENT as CNT_COMMENT,
dogovor.ID_CLIENT as CNT_ID_CLIENT, dogovor.ID_DOGOVOR_TYPE as CNT_ID_DOGOVOR_TYPE, dogovor.ID_INSURANCE_COMPANY as CNT_ID_INSURANCE_COMPANY, dogovor.TRANSIT as CNT_TRANSIT, dogovor.ID_CAR as CNT_ID_CAR, dogovor.ID_TERRITORY_USE as CNT_ID_TERRITORY_USE, dogovor.UNLIMITED_DRIVERS as CNT_UNLIMITED_DRIVERS, dogovor.INS_SUM as CNT_INS_SUM, dogovor.INS_PREM as CNT_INS_PREM, dogovor.KOEF_TER as CNT_KOEF_TER, dogovor.KOEF_BONUSMALUS as CNT_KOEF_BONUSMALUS, dogovor.KOEF_STAG as CNT_KOEF_STAG, dogovor.KOEF_UNLIMITED as CNT_KOEF_UNLIMITED, dogovor.KOEF_POWER as CNT_KOEF_POWER, dogovor.KOEF_PERIOD_USE as CNT_KOEF_PERIOD_USE, dogovor.KOEF_SROK_INS as CNT_KOEF_SROK_INS, dogovor.KOEF_KN as CNT_KOEF_KN, dogovor.BASE_SUM as CNT_BASE_SUM,
dogovor.ID_INSURANCE_CLASS as CNT_ID_INSURANCE_CLASS, dogovor.DATE_WRITE as CNT_DATE_WRITE, dogovor.DATE_BEGIN as CNT_DATE_BEGIN, dogovor.ID_PREV_DOG as CNT_ID_PREV_DOG, dogovor.DATE_INSERT as CNT_DATE_INSERT, dogovor.DATE_UPDATE as CNT_DATE_UPDATE, dogovor.USER_INSERT_NAME as CNT_USER_INSERT_NAME, dogovor.USER_UPDATE_NAME as CNT_USER_UPDATE_NAME ,
car.ARENDA as CAR_ARENDA, car.ID_CAR as CAR_ID_CAR, car.ID_PURPOSE_TYPE as CAR_ID_PURPOSE_TYPE, car.ID_CAR_TYPE as CAR_ID_CAR_TYPE, car.ID_PRODUCTER_TYPE as CAR_ID_PRODUCTER_TYPE, car.ID_CLIENT as CAR_ID_CLIENT, car.PTS_DATE as CAR_PTS_DATE, car.DATE_INSERT as CAR_DATE_INSERT, car.CAR_MARK as CAR_CAR_MARK, car.DATE_UPDATE as CAR_DATE_UPDATE, car.CAR_MODEL as CAR_CAR_MODEL, car.VIN_NUM as CAR_VIN_NUM,
car.YEAR_ISSUE as CAR_YEAR_ISSUE, car.POWER_KVT as CAR_POWER_KVT, car.POWER_LS as CAR_POWER_LS, car.MAX_KG as CAR_MAX_KG, car.NUM_PLACES as CAR_NUM_PLACES, car.SHASSI as CAR_SHASSI, car.KUSOV as CAR_KUSOV, car.GOS_NUM as CAR_GOS_NUM, car.PTS_SER as CAR_PTS_SER, car.PTS_NO as CAR_PTS_NO, car.FOREING as CAR_FOREING, car.COMMENTS as CAR_COMMENTS, car.USER_INSERT_NAME as CAR_USER_INSERT_NAME, car.USER_UPDATE_NAME as CAR_USER_UPDATE_NAME ,
client.ID_CLIENT as CLN_ID_CLIENT, client.SURNAME as CLN_SURNAME, client.NAME as CLN_NAME, client.MIDDLENAME as CLN_MIDDLENAME, client.INN as CLN_INN, client.DOC_SER as CLN_DOC_SER,
client.POSTINDEX as CLN_POSTINDEX, client.BIRTHDAY as CLN_BIRTHDAY, client.ID_CITY as CLN_ID_CITY, client.ID_REGION as CLN_ID_REGION, client.ID_COUNTRY as CLN_ID_COUNTRY, client.TOWN as CLN_TOWN, client.STREET as CLN_STREET, client.HOME as CLN_HOME, client.KORPUS as CLN_KORPUS, client.FLAT as CLN_FLAT, client.HOME_PHONE as CLN_HOME_PHONE, client.DOC_NUM as CLN_DOC_NUM, client.ID_SEX as CLN_ID_SEX, client.ID_FAMILY_STATE as CLN_ID_FAMILY_STATE, client.ID_CLIENT_TYPE as CLN_ID_CLIENT_TYPE, client.ID_TYPE_DOC as CLN_ID_TYPE_DOC, client.GROSS_VIOLATIONS as CLN_GROSS_VIOLATIONS, client.ID_INSURANCE_CLASS as CLN_ID_INSURANCE_CLASS, client.LICENCE_SER as CLN_LICENCE_SER, client.LICENCE_NO as CLN_LICENCE_NO, client.START_DRIVING_DATE as CLN_START_DRIVING_DATE,
client.DATE_INSERT as CLN_DATE_INSERT, client.DATE_UPDATE as CLN_DATE_UPDATE, client.IMPORT_DATE as CLN_IMPORT_DATE, client.WRITER_NAME as CLN_WRITER_NAME, client.ID_TYPE_LOSSED as CLN_ID_TYPE_LOSSED, client.CELL_PHONE as CLN_CELL_PHONE, client.BUSINESS_PHONE as CLN_BUSINESS_PHONE, client.LAST_CALL_DATE as CLN_LAST_CALL_DATE, client.REGION_CODE as CLN_REGION_CODE, client.COMMENTS as CLN_COMMENTS, client.USER_INSERT_NAME as CLN_USER_INSERT_NAME, client.USER_UPDATE_NAME as CLN_USER_UPDATE_NAME , CONCAT_WS(” “, DOG_SER, DOGNUMB) as FULL_NUM, CONCAT_WS(” “, carmark.MARK, car.CAR_MODEL) as FULL_MODEL, CONCAT_WS(” “, client.surname, client.name, client.middlename) as FULL_NAME , CONCAT_WS(”, “, if(client.town = ”, null, client.town), if(client.street = ”, null, client.street), if(client.home = ”, null, client.home), if(client.korpus = ”, null, client.korpus), if(client.flat = ”, null, client.flat)) as FULL_ADDRESS
from client_types, carmark, car_type, dogovor_type, dogovor
join client on dogovor.ID_CLIENT = client.ID_CLIENT
join car on dogovor.ID_CAR = car.ID_CAR
where (dogovor.ID_DOGOVOR_TYPE = dogovor_type.ID_DOGOVOR_TYPE) and
(DOGNUMB like ‘%123%’ )
or
(
((SURNAME like ‘%Иванов%’ ) and (client_types.ID_CLIENT_TYPE_GROUP = 1 and client_types.ID_CLIENT_TYPE = client.ID_CLIENT_TYPE))
)
or
(
(car.ID_CAR_TYPE = car_type.ID_CAR_TYPE and car.CAR_MARK = carmark.ID_CARMARK) and
(VIN_NUM like ‘%123%’ )
)
“
Т.е., используется like ‘%…%’. В документации написано, что при использовании like ‘%…%’ индексы не работают, а используется какой-то “Turbo Boyer-Moore algorythm” (вроде бы).
Работает очень медленно. Я ни разу не дождался окончания поиска даже по двум сущностям.
Поиск по договору - это поиск по трём. Решил Sphinx использовать. SphinxQL потому, что проще переписать для него.
Сейчас, как я понял, надо сделать три источника:
1.) Ист. клиентов.
2.) Ист. ТС.
3.) Ист. договоров.
И три индекса:
1.) Для клиента нужен индекс из 1.
2.) ТС имеет владельца, т.е. по ТС нужен индекс из 1 и 2.
3.) Для договоров из 1, 2, 3.
Проблема заключается в том, что, во-первых, у себя я так и не дождался окончания создания индекса, хотя бы по клиентам (но в таблице всего лишь ~15500 записей).
Тестовый индекс по таблице со 149 записями создаётся.
Почему ж так долго? Что я делаю не так?
Во-вторых, хотелось бы получать данные, а не ID.
Возможно это сделать средствами Sphinx (чтобы он, например, делал запрос к MySQL)?
Да, ещё с запросом я стормозил. Но даже с IN, всё-равно, очень медленно. :-(
Анатолий, спасибо, как раз назрела надобность использовать поисковый движок такого рода в проекте, Ваша статья оказалась очень кстати.