Что-то блог MODX на Хабре совсем зачах. Нужно его немного оживить. Хочу представить вам свой не особо новый компонент, который недавно был практически полностью переписан и расширен.
Компонент называется mSearch. Изначально он задумывался как простейший поиск по сайту, но с учетом морфологии русского языка. То есть, нужно было простое и легкое решение для любого сайта, без установки Sphinx и других серьезных систем.
В процессе гугления я натолкнулся на одну интересную реализацию этой задачи при помощи phpMorphy. Полнотекстовый поиск по таблице с индексом, с генерацией разных словарных форм. Идея мне приглянулась, под мои критерии она подходила и я написал свое решение, положив в основу этот метод.
mSearch
Это сниппет и плагин. Сниппет ищет, плагин индексирует документы при сохранении.
Установка, как обычно, из репозитория, в 4 клика. При этом, вам будет предложено скачать и установить словари phpMorphy для русского языка — не отказывайтесь.
Если вы устанавливаете расширение на рабочий сайт, нужно будет проиндексировать имеющиеся документы. Делается это просто:
[[!mSearch?
&indexer=`1`
&offset=`0`
&limit=`200`
]]
Первый параметр показывает, что мы не ищем, а индексируем, а второй и третий — ограничение выборки, для больших сайтов. Если документов много, а сервер дохлый — придется работать в несколько запусков, меняя значение offset, в данном примере сначала 0, потом 200, потом 400 и т.д.
Индексация нужна только один раз, после установки на сайт, если там есть документы. Потом индексировать будет плагин mSearchIndexer при сохранении документов.
Все параметры mSearch вы можете увидеть в свойствах сниппета, а сюда я напишу только основные:
- &indexer — включение индексации. Нужно только один раз, после установки.
- &indexFields — какие поля ресурса индексировать?
- &disablePhpMorphy — отключение phpMorphy. Поиск становится гораздо менее точным.
- &includeMS — при выводе результатов включать свойста товаров из miniShop.
- &includeTVs — при выводе товаров включать ТВ параметры.
- &includeTVList — список имен ТВ параметров, через запятую, для вывода.
- &parents — список родителей, в которых будет производиться поиск на глубину 10 вложений, через запятую.
- &returnIds — вместо оформленных результатов возвращать id найденных страниц, через запятую.
- &resources — список обязательных ресурсов, через запятую, в которых будет произведен поиск.
- &templates — искать только среди ресурсов с этими номерами шаблонов, через запятую.
- &tpl — шаблон оформления вывода.
- &where — JSON выражения для тонкой настройки вывода найденных ресурсов.
Параметры indexFields, includeTVs, includeTVList, disablePhpMorphy есть и у плагина. Они отвечают за индексацию ресурса при обновлении.
Также эти параметры влияют и на первичную индексацию (&indexer=`1`).
Обращая ваше внимание, что множество параметров не случайно называются как у getResources. Это означает, что и работают они так же. Сниппет прекрасно поддерживает вывод с пагинацией через getPage и может, в некоторых случая, спокойно заменять getResources.
Поиск идет по таблице индекса, что дает неплохую скорость, даже при большом количестве документов, проверял на ~6000 шт.
Конечно, этот метод не идеален, с релевантностью не все гладко, но лучше решения для русского языка и MODX в любом случае нет. Главное, на мой взгляд то, что можно довольно хорошо уточнить где искать, с каким шаблоном, среди каких родителей и т.д. Ну а параметр &where позволяет и вовсе, как угодно настроить поиск.
Погонять поиск можно тут. Учтите, что морфология работает только для русского языка.
Здесь можно посмотреть как выглядит SQL запрос. Там же чуть более подробный пример вызова сниппета.
Логичным применением mSearch стал поиск по товарам магазина, и вывод найденных результатов, вместо getResources. А это в свою очередь развилось в написание сниппета mFilter, для гибкой фильтрации найденных товаров.
mFilter
Это второй сниппет в mSearch. Он предназначен для динамической генерации фильтров для найденных (или заранее указанных) ресурсов.
Фильтры строятся для ТВ параметров ресурсов, иили свойств товаров miniShop.
Вы видите слева параметры, справа результаты поиска на моем демо-сайте по фразе «Sony». Возле каждого параметра есть циферки — это количество результатов, которое вы получите при выборе это параметра. То есть, все варианты фильтра просчитываются на лету, и невозможные комбинации отключаются.
Работает исключительно через Ajax (js скрипт для примера прилагается). При загрузке страницы выбираются все нужные свойства ресурсов для построения фильтров, кэшируются, и выводится форма фильтров. при каждом изменении формы, она отправляется на сервере и в ответ приходят результаты и состояние переключателей фильтра.
Работает довольно шустро, но на действительно больших объемах пока не проверял.
Основные параметры mFilter:
- &resources — список ресурсов для работы, через запятую. Если не указать, попытается поискать результаты через mFilter.
- &includeTVs — включить ТВ для генерации фильтров
- &includeTVList — использовать эти ТВ, через запятую
- &excludeTVList — не использовать эти ТВ, через запятую
- &includeMS — брать параметры miniShop для построения фильтра
- &includeMSList — какие именно поля товаров miniShop использовать для фильтра
- &sortFilters — порядок вывода фильтров, с префиксами, например: `tv_category,tv_subcategory,ms_add2,tv_color,tv_size,tv_action,ms_price`
- + если будете искать ресурсы, то любые параметры mSearch
- + любые параметры getPage иили getResourcesmsGetResources
Для вывода результатов фильтра необходимы сниппеты getPage, getResources (если используете miniShop — msGetResources).
Также требуются jquery плагины:
jQuery 1.7+ — основной помошник
jQueryUI 1.8+ — нужен только виджет slider для цен и других числовых значений
jQuery Form 2.7+ — отправка формы и прием ответа
Для вывода товаров из определенной категории магазина miniShop можно использовать такой сниппет (измените по вкусу):
if (!empty($_REQUEST['query'])) {return;}
$parent = $modx->resource->id;
$tmp = $modx->getChildIds($parent);
if (empty($tmp)) {return 0;}
$tpls = explode(',', $modx->getOption('minishop.goods_tpl'));
$q = $modx->newQuery('modResource', array('id:IN' => $tmp, 'template:IN' => $tpls, 'deleted:!=' => 1, 'published' => 1));
$q->select('id');
if ($q->prepare() && $q->stmt->execute()) {
$ids = $q->stmt->fetchAll(PDO::FETCH_COLUMN, 0);
return implode(',', $ids);
}
Заключение
Все чанки оформления и js скрипт для работы идут в комплекте. Конечно, не факт, что у вас все получится настроить как надо с первого раза, для этого нужны кое-какие знания MODX, jQuery и понимание работы Ajax. При всех «не работает!» первым делом смотрите в консоль своего браузера на предмет ошибок javascript.
Но я, как смог, постарался упростить задачу построения фильтра. И теперь, при определенном желании, вы сможете сделать это у себя на сайтемагазине.
Автор: bezumkin