Открыть список
Как стать автором
Обновить

Комментарии 41

Статья хорошая. Но вот такой вопрос. Я бы в такой ситуации поступил так — сделал бы из трез таблиц view с дополнительным полем source=enum{article, category, geo} а потом из этого view сделал бы таблицу с полнотекстовым поиском(ну или можно было бы сделать триггеры на изменение данных в исходных таблицах). Конечно морфологии тут не было бы(не postgres ведь)). В чем приемущество сфинкса перед таким вариантом?
Ну вот как раз в морфологии, и с релевантностью у сфинкса будут дела по-лучше, чем у mysql.
Ну вот видите, сколько действий вам нужно делать, чтобы организовать поиск с помощью БД. Плюс вы столкнетесь со следующими проблемами:
1. БД сможет использовать только полнотекстовый индекс, а если у вас еще будет фильтрация по другим параметрам, это будет производиться без индексов, т.е. медленно. В статье я поставил простую задачу, на самом деле мне нужно было фильтровать записи по десятку параметров;
2. В Sphinx существует множество режимов поиска, в каждом из них идут свои «бонусы»;
3. С помощью прстого указания между режимами SPH_MATCH_ALL, SPH_MATCH_ANY можно задать поиск по всех словам из фразы или по любому из слов и все это с учетом морфологии;
4. В режиме SPH_MATCH_EXTENDED, помимо стандартных операторов AND, OR, NOT можно задавать близость слов: «example program»~5 – такое условие говорит Sphinx, что между словами example и program должно быть не более 5-ти слов; а также порог на количество слов: «Петя Пупкин пошел гулять по лесу»/3 возвращает те записи, где встречается хотя бы 3 из 6 слов в заданной фразе.
5. В Sphinx введен режим SPH_MATCH_FULLSCAN, когда поисковая фраза пустая и заданы только фильтры и группирование. В документации пишут, что выборка записей по фильтрам идет в некоторых случаях даже быстрее, чем в MySQL. Я также перевел некоторые запросы с большими условиями на Sphinx, чтобы разгрузить БД.
6. В индекс может понадобиться включить что-то не хранящееся в БД, а Sphinx, как я писал, умеет искать и по xml, html, почте и др.
На более-менее приличной по объему БД сфинкс в разы (а то и в десятки раз) сделает мускуль по производительности. Проверено.
Большое спасибо за статью! Как раз уже начинал копать в сторону сфинкс, скоро придется тоже поиск организовывать на сайте.
А кармы, я думаю, у вас будет скоро много(я принял в этом участие :) ) и сможете сами создать блог)
Демона останавливать не обязательно, достаточно indexer'у дать параметр --rotate название_индкса или --rotate all
Да, спасибо, это очень ценно, упустил этот момент.
Создал: habrahabr.ru/blogs/sphinx

Спасибо за статью, для своих проектов на symfony использовали lucene. Теперь, думаю стоит посмотреть в сторону Sphinx.
Спасибо за блог!
Он только под Виндовс? Жаль
Нет, вы что) ставится везде, где только можно — и Linux, и макось.
Вот список из оф. документации:
– Linux 2.4.x, 2.6.x (various distributions)
– Windows 2000, XP
– FreeBSD 4.x, 5.x, 6.x
– NetBSD 1.6, 3.0
– Solaris 9, 11
– Mac OS X
Кто он? Sphinx кросс-платформенный
>> Представьте, как пришлось бы попотеть, чтобы организовать такой поиск с помощью БД!
те же самые 3 запроса, которые использовались при индексации, объединённые через UNION.
Я имел ввиду в том числе и эффективность выполнения таких запросов.
Если записей, скажем, 4млн, сфинкс оставит далеко позади mysql по скорости, тем более при полнотекстовом поиске.
прочитай внимательнее его абзац :-)
это предложение преподносится в контексте того, что «как круто, сфинкс умеет индексировать из N источников». Т.е. фичей преподносится возможность индексации кучи сорсов, а не производительность — с этой точки зрения мой комментарий вполне уместен: mysql через UNION может делать то же самое. м?

по поводу скорости — отлично представляю насколько сфинкс куче mysql.
Да и для Symfony есть неплохой плагин, позволяющий работать с Sphinx
Создание индекса Sphinx'а надо периодически запускать, или он это делает сам?
Да, надо запускать, повесить в кроне задачу, например.
Я бы создал все-таки три индекса. Sphinx API позволяет искать по нескольким индексам сразу. Зато при наличии трех индексов вместо одного мы можем спокойно искать по каждому из них отдельно в случае надобности.
И второе преимущество различных индексов — не приходится вводить лишнии манипуляции с id-шниками
Фильтр по row_type позволить искать по отдельным индексам, а со вторым в принципе согласен.
Чтобы не писать конфиг коннекта в каждом source, его можно определить в отдельном source (скажем, generic) и во всех остальных его наследовать. Так будет много проще
НЛО прилетело и опубликовало эту надпись здесь
source generic {конфиг коннекта}
source foo : generic {конфиг для нашего конктретного source}
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
По поводу источника данных.
View — я бы не советовал использовать, так как при достаточно большом обьеме данных, даже используя частичную выборку из view вы положите базу данных ($start, $stop). Плюс если вы хотите действительно не напрягать mysql то не слудет при обращении в view делать какие либо условия на больших обьемах данных (например: where source = 'article', limit и тд, но это только пример 8) ).

Стоит делать отдельные индексы (article, category, geo).
Какие плюсы мы получим:
1. индексы могут содержать разное количество полей, часть полей могут быть в будущем использованы для специфического поиска к примеру по категориям.
2. можно гибко работать с весами для разных индесков
3. можно производить реиндексацию только изменившегося индекса (при полной реиндексации), а это снижение нагрузки. В данном случае чаще будет обновляться article, чем category и geo.

Ну и наспоследок, при использовании Sphinx сразу закладывайте в архитектуру работу с частичными индексами (индексы содержащие изменившиеся данные за определенный промежуток времени) и их обьединением с основным индексом.
Замечания все верны, но, к сожалению, все уместить в одну статью нереально. Если у хабрасообщества будет желание, я напишу продолжение.

PS. Эту статью меня попросили перевести на английский, надеюсь, это поспособствует популяризации Sphinx за рубежом :)
когда же будет продолжение?
Уже приходилось прикручивать Sphinx к Symfony для организации поиска на новой версии проекта своей компании. Что я могу сказать по этому поводу. Порадовала производительность — поиск просто летает, страницы с поисковыми запросами отдаются быстрее всех на сайте! В то же время пришлось немало помучиться, наступив на неслабое количество граблей. Во-первых крайне не понравился написанный на PHP 4 и крайне неудобный в использовании Sphinx API. Я решил написать более удобную обертку, использующую всю мощь ООП в PHP 5. В не меньшей степени раздражало и необходимость применения сфинксовых костылей типа метода SetArrayResult(). Ну и самый пипец был уже после выкладки — неожидано выяснилось, что пустой поиск поиск по одному из индексов выдает довольно странную ошибку. К счастью она не я первый на нее наткнулся:

www.sphinxsearch.com/forum/view.html?id=2070

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

Одним словом вывод один — для работы со Sphinx нужно хорошо уметь работать напильником :).
Такая же история ;) И класс sfSphinxClient толком наследовать не получается, потому как private $res, а чужой код мы стараемся не изменять ;)
С вашей версией обёртки ознакомиться где-нибудь можно?
SELECT id * 10 + 1 as id — скажите пожалуйста о какой уникальности здесь идёт речь ??
К примеру:
21 * 10 + 1 = 211
22 * 10 + 1 = 221
Собственно хочется спросить — и чо? В чём разница между 21, 22 и 211, 221?
Понятно, что id одной таблицы уникальны. Здесь же, если вы заметили, объединяются записи из 3-х таблиц, а в этом случае у нас вполне могут попасться записи с одинаковым id=21, например. Поэтому для первой таблицы 21 * 10 + 1 = 211, для второй 21 * 10 + 2 = 212 и т.п. Таким способом можно объединить до 10-ти таблиц.
Если этого не хватает, меняем 10 на 100, и проблема решается на долгую перспективу.
я просто думал, что должно быть какое то по оригинальней решение ))
Ведь если, грубо говоря, в одной таблице записей не больше 50, а во второй больше 500, то даже делая id * 10 + 1 as id, то идентификаторы всё равно будут пересекаться… т.е. это далеко не универсальное решение. Так что эта «перспектива» весьма туманна. Я как то читал на баше пост, где тип жаловался на инфляцию и говорил, что ему в его какой то биллинговой софтине пришлось все типы дынных int заменить на long из-за того, что цены быстро растут)))

P.S. Всё равно не ясно, что в этой комбинации решает еденица — id * 10 + 1? ))
с чего бы им пересекаться? все идентификаторы первой таблицы кончаются на 1, второй — на 2.
с чего бы им пересекаться? все идентификаторы первой таблицы кончаются на 1, второй — на 2.
Кстати говоря, на 0.9.9 такое уже не сработает — Sphinx требует совпадения полей для всех источников индекса.
Спасибо, статья очень помогла для старта, тоже была задача поиска по разношерстным данным.
Хотел бы лишь подчеркнуть небольшие неточности и недосказанности.
Во-первых,
>sql_query_info
>Ну и последний параметр — это маска запроса, который будет извлекать нужную нам информацию по найденным id
стоить заметить, что этот параметр работает только при поиске через консоль, то есть предназначен для дебага и через API работать не будет

Во-вторых,
при указании в индексе двух и более источников, нужно позаботиться о том, чтобы в них было одинаковое количество полей,
можно это решить как '' as `required_field_name` для несовпадающих поле или использовать для каждого источника свой индекс

Это те вещи с которыми столкнулся лично я, может помогут кому-то еще.
Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.