Pull to refresh

mSearch: поиск + фильтр для MODX Revolution

Reading time5 min
Views35K


Что-то блог 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 позволяет и вовсе, как угодно настроить поиск.

Погонять поиск можно тут. Учтите, что морфология работает только для русского языка.

Логичным применением 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 и\или getResources\msGetResources

Для вывода результатов фильтра необходимы сниппеты getPage, getResources (если используете miniShop — msGetResources).

Также требуются jquery плагины:
jQuery 1.7+ — основной помошник
jQueryUI 1.8+ — нужен только виджет slider для цен и других числовых значений
jQuery Form 2.7+ — отправка формы и прием ответа

Для вывода товаров из определенной категории магазина miniShop можно использовать такой сниппет getCatIds:
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);
}

Пример вызова:
[[!mFilter?
&resources=`[[!getCatIds]]`
&includeTVs=`1`
&includeTVList=`category,color,size,action`
&includeMS=`1`
&includeMSList=`add2,price`
&tpl=`tpl.msGoods.row`
&templates=`5`
&sortFilters=`tv_category,tv_subcategory,ms_add2,tv_color,tv_size,tv_action,ms_price`
]]


Заключение


Все чанки оформления и js скрипт для работы идут в комплекте. Конечно, не факт, что у вас все получится настроить как надо с первого раза, для этого нужны кое-какие знания MODX, jQuery и понимание работы Ajax. При всех «не работает!» первым делом смотрите в консоль своего браузера на предмет ошибок javascript.

Но я, как смог, постарался упростить задачу построения фильтра. И теперь, при определенном желании, вы сможете сделать это у себя на сайте\магазине.

Вы можете посмотреть в админке моего демо-сайта, как включены фильтр и поиск. Логин и пароль: test.

Кстати
Вся работа над mFilter была заказа и оплачена веб-студией Simple Dream.
Tags:
Hubs:
+11
Comments5

Articles