В поисках верного пути: как фасетная навигация влияет на SEO (перевод). В поисках верного пути: как фасетная навигация влияет на SEO (перевод) Решения для фасетной навигации

{ "query": { "and": [ { "terms": {"country": ["be", "fr"]} }, { "terms": {"category": ["books", "movies"]} } ] } }

Для счетчиков мы можем использовать встроенные агрегаты из Elasticsearch. Каждый из двух фасетов хранится как одно поле в индексе, поэтому мы можем использовать агрегирование терминов в каждом из этих полей. Агрегация вернет счетчик за значение этого поля.

{ "query": { "and": [ { "terms": {"country": ["be", "fr"]} }, { "terms": {"category": ["books", "movies"]} } ] }, "aggregations": { "countries": { "terms": {"field": "country"} }, "categories": { "terms": {"field": "category"} } } }

Если бы вы выполнили этот запрос, вы заметите, что счетчики отключены. В двух не отобранных странах, в Португалии и Бразилии, есть счетчик 0. Хотя есть фактические результаты, если мы хотим их выбрать (из-за ORвнутренней грани). Это происходит потому, что по умолчанию Elasticsearch выполняет свои агрегирования в результирующем наборе. Это означает, что если вы выберете Францию, фильтры другой страны будут иметь счет 0, потому что в результирующем наборе содержатся только элементы из Франции.

Чтобы исправить это, нам нужно дать команду Elasticsearch выполнить агрегацию во всем наборе данных, игнорируя запрос. Мы можем сделать это, определив наши скопления как глобальные.

{ "query": { "and": [ { "terms": {"country": ["be", "fr"]} }, { "terms": {"category": ["books", "movies"]} } ] }, "aggregations": { "all_products": { "global": {}, "aggregations": { "countries": { "terms": {"field": "country"} }, "categories": { "terms": {"field": "category"} } } } } }

Если бы мы просто сделали это, наши счетчики всегда были бы одинаковыми, потому что они всегда будут рассчитывать на весь набор данных, независимо от наших фильтров. Наши агрегаты должны стать немного более сложными, чтобы это работало, нам нужно добавить к ним фильтры. Каждое агрегирование должно рассчитывать на набор данных со всеми применяемыми фильтрами, за исключением собственных. Таким образом, агрегация за счет во Франции рассчитывает на набор данных с применением фильтра категории, но не фильтр стран:

{ "query": { "and": [ { "terms": {"country": ["be", "fr"]} }, { "terms": {"category": ["books", "movies"]} } ] }, "aggregations": { "all_products": { "global": {}, "aggregations": { "countries": { "filter": { "and": [ { "terms": {"category": ["books","movies"]} } ] }, "aggregations": { "filtered_countries": { "terms": {"field": "country"} } } }, "categories": { "filter": { "and": [ { "terms": {"country": ["be","fr"]} } ] }, "aggregations": { "filtered_categories": { "terms": {"field": "category"} } } } } } } }

{ "took": 153, "timed_out": false, "_shards": { "total": 5, "successful": 5, "failed": 0 }, "hits": { "total": 3, "max_score": 0, "hits": ["..."] }, "aggregations": { "all_products": { "doc_count": 21, "filterted categories": { "doc_count": 13, "categories": { "doc_count_error_upper_bound": 0, "sum_other_doc_count": 0, "buckets": [ { "key": "movies", "doc_count": 6 }, { "key": "music", "doc_count": 4 }, { "key": "books", "doc_count": 3 } ] } }, "filtered_countries": { "doc_count": 15, "countries": { "doc_count_error_upper_bound": 0, "sum_other_doc_count": 0, "buckets": [ { "key": "fr", "doc_count": 6 }, { "key": "br", "doc_count": 4 }, { "key": "be", "doc_count": 3 }, { "key": "pt", "doc_count": 2 } ] } } } } }

Yii2 framework $terms = QueryHelper:: terms ("categories.name" , "my category" ) ; $nested = QueryHelper:: nested ("string_facet" , QueryHelper:: filter ([ QueryHelper:: term ("string_facet.facet_name" , [ "value" => $id , "boost" => 1 ] ) , QueryHelper:: term ("string_facet.facet_value" , [ "value" => $value , "boost" => 1 ] ) , ] ) ) ; $filter = QueryHelper:: should ($nested ) ;

Современный человек старается тратить на покупки все меньше времени. Медленные каталоги товаров отталкивают покупателей, магазин теряет клиентов и часть прибыли. Сделайте свой интернет-магазин привлекательнее вместе с технологией фасетного Фасетный - т.е. предопределенный. поиска. Создайте фасетные индексы и значительно ускорьте поиск товаров и работу всего каталога.

Примечание: Механизм фасетного поиска доступен с версии 15.0.1 модуля Информационные блоки и интегрирован с компонентом Компонент - это программный код, оформленный в визуальную оболочку, выполняющий определённую функцию какого-либо модуля по выводу данных в Публичной части. Мы можем вставлять этот блок кода на страницы сайта без непосредственного написания кода. Умный фильтр Компонент подготавливает фильтр для выборки из инфоблока и выводит форму фильтра для фильтрации элементов. Компонент должен подключаться перед компонентом вывода элементов каталога, иначе список элементов фильтроваться не будет. Компонент стандартный, входит в дистрибутив модуля и содержит три шаблона: .default , visual_horizontal и visual_vertical . (Последние два шаблона не поддерживаются, остались для сохранения совместимости.)

В визуальном редакторе компонент расположен по пути Контент > Каталог > Умный фильтр .

Компонент относится к модулю Информационные блоки.

Подробнее о фасетном поиске

Рассмотрим на примере:

Мы заходим в интернет-магазин и в фильтре выбираем, что нам нужна футболка красного цвета:

  • Без фасетного поиска фильтр начал бы перебирать весь список товаров на соответствие товару «Футболка» со свойством цвет «Красный», что заняло бы немало времени при большом количестве товара;
  • Если настроить фасетный поиск, то создаются готовые поисковые наборы товаров по некоторому значению свойства (фасетные индексы ), т.е. варианты возможных запросов Например красная футболка, все товары черного цвета из хлопка, платья размера XS и т.д. в умном фильтре просчитаны заранее и результат выдается сразу. Такой поиск товаров работает намного быстрее.

Создадим фасетные индексы за несколько простых действий:

Нужно ли пересоздавать фасетные индексы?

Фасетные индексы пересоздаются автоматически или требуется пересоздать их вручную в зависимости от произведенных действий:

Автоматически Добавили новые или отредактировали существующие товары .
не создают новых свойств.
Вручную Система подскажет вам об этом с помощью сообщения вверху страниц
административного раздела.
Добавили новые или отредактировали разделы каталога .
При добавлении нового или удалении свойства из умного фильтра .
При выгрузке товаров, например, из 1С, если товары создают новые свойства.

Фасетный поиск улучшает работу каталога товаров. Для его использования необходимо:

  • Создать фасетные индексы для каталога с товарами;
  • Следить за оповещением о необходимости пересоздания индексов вручную.
  • Мы кратко рассмотрели установку и базовый синтаксис PINQ, портированную на PHP версию LINQ. В этой статье мы рассмотрим, как использовать PINQ для имитации возможности фасеточного (аспектного) поиска в MySQL.

    В этой статье мы не будем рассматривать все аспекты фасеточного поиска. Интересующиеся люди могут поискать подходящую информацию в интернете.

    Типичный фасеточный поиск работает следующим образом:

    • Пользователь вводит ключевое слово, или несколько ключевых слов для поиска. Например, “маршрутизатор” для поиска продуктов, у которых в слово “маршрутизатор” встречается в описании, ключевых словах, названии категории, тегах и проч.
    • Сайт возвращает список продуктов, подходящих под эти критерии.
    • Сайт предоставляет несколько ссылок для подстройки условий поиска. Например, может позволить указать конкретных производителей маршрутизаторов, либо задать диапазон цен, или другие особенности.
    • Пользователь может продолжать указывать дополнительные критерии поиска для того, чтобы получить интересующий его набор данных.

    Фасеточный поиск весьма популярен, и является мощным инструментом, его можно наблюдать почти на любом сайте, связанном с электронной коммерцией.

    К сожалению, фасеточный поиск не встроен в MySQL. Так что же нам делать, если мы всё-таки используем MySQL, но хотим дать пользователю такую возможность?

    С помощью PINQ, в котором реализован аналогичный, мощный и простой подход, мы можем добиться такого поведения, как если бы мы использовали другие движки баз данных.

    Расширяем демонстрационный пример из первой части

    Замечание : весь код из этой части, и из первой части, можно найти в репозитории .

    В этой статье мы расширим демонстрационный пример из первой части, добавив к нему существенное улучшение в виде фасеточного поиска.

    Начнём с index.php , добавив в него следующие строки:

    $app->get("demo2", function () use ($app) { global $demo; $test2 = new pinqDemo\Demo($app); return $test2->test2($app, $demo->test1($app)); }); $app->get("demo2/facet/{key}/{value}", function ($key, $value) use ($app) { global $demo; $test3 = new pinqDemo\Demo($app); return $test3->test3($app, $demo->test1($app), $key, $value); });

    Первый маршрут переносит нас на страницу для просмотра всех записей, подходящих под поиск по ключевому слову. Чтоб не усложнять пример, мы выбираем все книги из таблицы book_book . На ней также будут отображён результирующий набор данных и набор ссылок для конкретизации критериев поиска.

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

    Но в этом примере мы не будем реализовывать такое поведение - все фильтры будут отражать граничные значения оригинального набора данных. Это первое ограничение и первый кандидат на улучшение в нашем демонстрационном примере.

    Как видно в вышеприведённом коде, реальные функции располагаются в другом файле, под названием pinqDemo.php . Давайте взглянем на соответствующий код, который предоставляет возможность фасеточного поиска.

    Класс аспекта

    Первым делом создадим класс, представляющий аспект. В целом, аспект должен содержать несколько свойств:

    • Данные, которыми он оперирует ($data )
    • Ключ, по которому производится группировка ($key )
    • Тип ключа ($type). Может быть одним из следующих:
      • указывать полную строку, для точного совпадения
      • указывать часть строки (обычно - начальную), для поиска по шаблону
      • указывать диапазон значений, для группировки по диапазону
    • если тип ключа - диапазон значений, необходимо определить шаг значения для определения нижней и верхней границы диапазона; или же если тип - часть строки, необходимо указать, сколько первых букв будет использоваться для группировки ($range)

    Группировка - наиболее критичная часть аспекта. Вся агрегированная информация, которую, возможно, сможет вернуть аспект, зависит от критериев группировки. Обычно наиболее используемыми критериями поиска являются “Полная строка”, “Часть строки”, или “Диапазон значений”.

    Namespace classFacet { use Pinq\ITraversable, Pinq\Traversable; class Facet { public $data; // Оригинальный набор данных public $key; // поле, по которому производится группировка public $type; // F: вся строка; S: начало строки; R: диапазон; public $range; // играет роль, только если $type != F ... public function getFacet() { $filter = ""; if ($this->type == "F") // вся строка { ... } elseif ($this->type == "S") // начало строки { ... } elseif ($this->type == "R") // диапазон значений { $filter = $this->data ->groupBy(function($row) { return floor($row[$this->key] / $this->range) * $this->range; }) ->select(function (ITraversable $data) { return ["key" => $data->last()[$this->key], "count" => $data->count()]; }); } return $filter; } } }

    Главная функция этого класса - вернуть отфильтрованный набор данных, основываясь на исходном наборе данных, и свойствах аспекта. Из кода видно, что для различных типов счетов используются различные способы группировки данных. В вышеприведённом коде мы показали, как может выглядеть код, если мы группируем данные по диапазону значений с шагом, указанным в $range .

    Задаём аспекты и отображаем исходные данные

    Public function test2($app, $data) { $facet = $this->getFacet($data); return $app["twig"]->render("demo2.html.twig", array("facet" => $facet, "data" => $data)); } private function getFacet($originalData) { $facet = array(); $data = \Pinq\Traversable::from($originalData); // 3 примера создания различных объектов аспектов, и возврат аспектов $filter1 = new \classFacet\Facet($data, "author", "F"); $filter2 = new \classFacet\Facet($data, "title", "S", 6); $filter3 = new \classFacet\Facet($data, "price", "R", 10); $facet[$filter1->key] = $filter1->getFacet(); $facet[$filter2->key] = $filter2->getFacet(); $facet[$filter3->key] = $filter3->getFacet(); return $facet; }

    В методе getFacet() мы делаем следующее:

    • Конвертируем оригинальные данные в объект Pinq\Traversable для последующей обработки
    • Создаём три аспекта. Аспект ‘author’ будет группировать по полю author , и реализует группировку по всей строке; аспект ‘title’ - по полю title с группировкой по части строки (по первым 6 символам); аспект ‘price’ - по полю price с группировкой по диапазону (с шагом 10)
    • Наконец, извлекаем аспекты и возвращаем их функции test2 , чтобы их можно было вывести в шаблон для отображения
    Вывод аспектов и отфильтрованных данных

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

    Мы уже создали маршрут ("demo2/facet/{key}/{value}") для вывода результатов фасеточного поиска и ссылок фильтров.

    Маршрут принимает два параметра, в зависимости от ключа, по которому производится фильтрация, и от значения для этого ключа. Функция test3 , которая привязана к этому маршруту, представлена ниже:

    Public function test3($app, $originalData, $key, $value) { $data = \Pinq\Traversable::from($originalData); $facet = $this->getFacet($data); $filter = null; if ($key == "author") { $filter = $data ->where(function($row) use ($value) { return $row["author"] == $value; }) ->orderByAscending(function($row) use ($key) { return $row["price"]; }) ; } elseif ($key == "price") { ... } else //$key==title { ... } return $app["twig"]->render("demo2.html.twig", array("facet" => $facet, "data" => $filter)); }

    В основном, в зависимости от ключа, мы применяем фильтрацию (анонимную функцию в выражении where), согласно переданному значению, и получаем следующий набор отфильтрованных данных. Также мы можем задать порядок фильтрации данных.

    Наконец, мы отображаем исходные данные (вместе с фильтрами) в шаблоне. Этот маршрут использует тот же шаблон, который мы использовали в " demo2 ".

    Search Bar

      {% for k, v in facet %}
    • {{k|capitalize}}
      • {% for vv in v %}
      • {{vv.count}}{{vv.key}}
      • {%endfor%}
      {%endfor%}

    Нужно помнить, что аспекты, генерируемые нашим приложением, являются вложенными массивами. На первом уровне это массив всех аспектов, и, в нашем случае их три (соответственно, для author , title , price).

    У каждого аспекта есть массив “ключ-значение”, так что мы можем итерировать его обычными методами.

    Заметьте, как мы строим URL для наших ссылок. Мы используем и ключ внешнего цикла (k), и ключи внутренних циклов (vv.key) в качестве параметров для маршрута ("demo2/facet/{key}/{value}"). Размер массивов (vv.count) используется для отображения в шаблоне.

    На первом изображении представлен изначальный набор данных, а на второй - отфильтрованный по диапазону цен от 0$ до 10$, и отсортированный по автору.

    Здорово, у нас получилось имитировать фасеточный поиск в нашем приложении!

    Прежде, чем завершить эту статью, необходимо напоследок взглянуть на наш пример, и определить, что же можно улучшить, и какие у нас есть ограничения.

    Возможные улучшения

    В общем, это очень элементарный пример. Мы всего лишь прошлись по базовому синтаксису и концепциям, и реализовали их в виде рабочего примера. Как ранее было сказано, у нас есть несколько областей, которые можно улучшить для большей гибкости.

    Нам необходимо реализовать “наложение” критерий поиска, так как текущий пример ограничивает нас возможностью применить фильтрацию поиска только к оригинальному набору данных, применить фасеточный поиск к уже отфильтрованному результату нельзя. Это самое большое улучшение, которое я могу представить.

    Ограничения

    Фасеточный поиск, реализованный в этой статье, имеет серьёзные ограничения (что, возможно, относится и к другим реализациям фасеточного поиска):

    Мы каждый раз выбираем данные из MySQL

    Это приложение использует фреймворк Silex. Как и в любом фреймворке с единой точкой входа, вроде Silex, Symfony, Laravel, его файл index.php (или app.php) вызывается каждый раз, когда происходит анализ маршрута, и выполняются функции контроллера.

    Если посмотреть в код в нашем index.php , можно обратить внимание, что следующая строчка кода:

    $demo = new pinqDemo\Demo($app);

    вызывается каждый раз, когда отображается страница приложения, что значит, что каждый раз выполняются следующие строки кода:

    Class Demo { private $books = ""; public function __construct($app) { $sql = "select * from book_book order by id"; $this->books = $app["db"]->fetchAll($sql); }

    Будет ли лучше, если мы не будем использовать фреймворк? Что ж, несмотря на факт того, что разрабатывать приложения без фреймворков, является не очень хорошей идеей, могу сказать, что мы встретимся с теми же проблемами: данные (и состояние) не сохраняются между разными HTTP запросами. Это фундаментальная характеристика HTTP. Этого можно избежать, используя механизмы кеширования.

    Мы сэкономили несколько SQL запросов, используя аспекты. Вместо того, чтобы передать один select запрос на выборку данных, и три запроса group by с соответствующими условиями where , мы выполнили только один запрос where , и использовали PINQ для получения агрегированной информации.

    Заключение

    В этой части мы реализовали возможность фасеточного поиска по коллекции книг. Как я и сказал, это всего лишь маленький пример, который есть куда ещё улучшать, и у которого есть ряд ограничений.

    В сегодняшнем уроке мы с вами попробуем воссоздать имитацию фасетного (фасеточного) поиска средствами Javascript. Я подразумеваю, что вы уже знаете что такое фасетный поиск, раз читаете данный туториал, в противном случае погуглите или загляните на Amazon или мою Демку .

    Для начала нам понадобится библиотека github.com/eikes/facetedsearch. Скачайте её и подключите файл facetedsearch.js к нашему проекту. Так же нам понадобятся библиотеки jQuery и Underscore.

    Дисклеймер: Я понимаю, что JQ уже давно не торт, но использую его как привычный синтаксический сахар, вы можете перепилить это под более привычные вам библиоетки или на ванильном JS.

    Итак для начала сделаем простенькую разметку с подключенными зависимостями:

    Document // Сюда мы выведем фасетные фильтры // А тут будут наши элементы

    Теперь нам нужно описать настройки нашего приложения и создать шаблон вывода элементов массива которые мы будем сортировать при помощи фасетов:

    $(function(){ var item_template = // Описывем шаблон "" + "" class="img-responsive">" + ", " + "

    " + "" + ", " + ", " + "

    " + "

    " + ""; settings = { items: example_items, facets: { // Указывем категории фасетов "category" : "What Category", "continent" : "Which Continent", "language" : "Programming Language" }, resultSelector: "#results", // DOM элемент куда мы выводим результаты facetSelector: "#facets", // DOM элемент для фасетов resultTemplate: item_template, paginationCount: 8, // Колличество элементов на страницу orderByOptions: {"firstname": "First name", "lastname": "Last name", "category": "Category", "RANDOM": "Random"}, facetSortOption: {"continent": ["North America", "South America"]} } $.facetelize(settings); });

    Ну и собственно создать сам JSON массив с элементами для отображения в нашем фасетном поиске на JS:

    Var items = [ { "firstname": "Mary", "lastname": "Smith", "imageURL": "http://lorempixel.com/150/150/cats/2", "description": "Sed Ea Amet. Stet Voluptua. Nonumy Magna Takimata ", "category": "Mouse", "language": ["Smalltalk", "XSLT"], "continent": "Africa" }, { "firstname": "Patricia", "lastname": "Johnson", "imageURL": "http://lorempixel.com/150/150/cats/3", "description": "Ut Takimata Sit Aliquyam Labore Aliquyam Sit Sit Lorem Amet. Ipsum Rebum. ", "category": "Lion", "continent": "North America" }, ... ];

    Данный массив я бы вынес в отдельный JS файл который бы формировался динамически, из БД например.

    Вот собственно и всё, мы получаем фасетный поиск на JavaScript и можем его кастомизировать. Далее я привожу переведённую документации библиотеки, где вы можете подсмотреть необходимые вам триггеры.

    Документация Функции

    Две функции экспортируются в пространство имен jQuery.

    facetelize Используется для инициализации фасетного поиска с заданными настройками.

    facetUpdate Может использоваться, если вы хотите изменить состояние фасетного поиска извне.

    Настройки объектов

    items: Массив элементов, которые будут отфильтрованы и отсортированы в процессе.

    facets: Объект, для которого ключи соответствуют ключам элементов и значениям, является заголовком для этого фасета. Элементы будут отфильтрованы на основе того, какое значение они имеют для этих ключей.

    orderByOptions: Подобно фасетам, за исключением того, что эти пары «ключ-значение» используются только для сортировки. Когда ключ RANDOM включен, результаты могут быть рандомизированы.

    facetSelector: Это селектор, который используется для поиска DOM-узла, из которого выбираются фильтры фасетов.

    resultSelector: Это селектор, который используется для поиска DOM-узла, где отображаются результаты.

    resultTemplate: Строка, которая используется Underscore шаблонизатором Для рендеринга каждого элемента из массива items . Следующие атрибуты добавляются к каждому элементу, который также можно использовать в шаблоне: batchItemNr , batchItemCount и totalItemCount .

    state: Этот объект сохраняет текущие фильтры, сортирует: currentResult и прочие. Вы можете предоставить строку orderBy или объект filters для их предварительной настройки.

    enablePagination: Boolean для включения пагиналора и кнопи "load more", по умолчанию true .

    paginationCount: Если включен пагинатор, задаёт количество элементов на страницу, по умолчанию - 50.

    facetSortOption: Используйте эту функцию, чтобы изменить порядок элементов фасетов. Принимает объект, в котором ключи соответствуют именам фасетов и значениям в массив значений фасетов, которые могут быть расположены в том порядке, в котором вы хотели бы их видеть. В этом примере будут отсортированы континенты в другом порядке, элементы, не включенные в массив, будут добавлены в алфавитном порядке:

    FacetSortOption: {"continent": ["North America", "South America"]}

    Есть еще несколько шаблонов, пожалуйста, посмотрите исходный код facetedsearch.js , чтобы увидеть все доступные параметры шаблона.

    События

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

    facetuicreated: Вы можете привязать эту функцию к DOM элементу settings.facetSelector который должен быть уведомлен, когда пользовательский интерфейс был создан.

    facetedsearchresultupdate: Вы можете привязать эту функцию к DOM элементу settings.resultSelector что бы получить уведомление о результатах обновления.

    facetedsearchfacetclick: Это событие вызывается при щелчке фасета и его срабатывании на settings.facetSelector элементе. Который получает идентификатор фасета как аргумент.

    facetedsearchorderby: Это событие вызывается при щелчке элемента сортировки по элементу settings.facetSelector. Он получает ID order в качестве аргумента.

    $(settings.resultSelector).bind("facetedsearchresultupdate", function(){ // do something, maybe });

    Умный фильтр или Фасетный поиск – это фильтр по категориям товара, которую можно видеть в крупных интернет магазинах и том же яндекс.маркете. Он помогает последовательно сортировать товары с нужными пользователю свойствами, отсеявая все лишнее. Это очень удобная опция, позволяющая быстро найти нужный товар или материал на сайте.

    И так давайте перейдем непосредственно к установке и настройке нужных нам модулей

    Для начала нам понадобятся скачать и установить следующие модули: Search API , Search API Database Search , Entity API и Views .

    На странице модулей включаем:

    • Search API
    • Search views
    • Database search
    • Entity API
    • Views
    • Views UI
    • Ctools
    Создание поискового сервера

    Идем в Конфигурация > Поиск и метаданные > Search API (/admin/config/search/search_api) и нажимаем Добавить сервер .
    Затем вводим имя сервера, в выпадающем списке Класс сервиса (Service class) выбираем Database service и сохраняем.

    Создание индекса

    Идем в Конфигурация > Поиск и метаданные > Search API (/admin/config/search/search_api), жмем Добавить сервер (Add index) .
    Вводим название индекса, в поле Тип элемента (Item type) выбираем ‘Материал ‘, в поле Сервер выбираем Database server , жмем Создание индекс.


    В открывшейся форме отмечаем галочками поля, по которым будет производится сортировка, и сохраняемся.
    Чтобы можно было делать сортировку по названию ноды, включаем title и напротив него в выпадающем списке выбираем тип string , а не fulltext . По fulltext сортировку делать нельзя.

    В следующей открывшейся форме Фильтры (workflow) я оставил все по умолчанию, переходим на вкладку Просмотр (Status ), и нажимаем Индексировать сейчас (Index Now ).
    После завершения индексации, создадим страницу поиска.

    Создание страницы поиска

    Идем в Structure > Views и жмем Добавить новое представление (Add new view) .
    В новом представление в выпадающем списке Показать (Show) выбираем ранее созданный нами индекс, остальные поля (название, title и путь) заполняете так как вам нужно.


    Далее нажимаем Сохранить и настроить (Continue & edit), настраиваем представление как обычно. В критериях фильтрации я добавил показ только опубликованных материалов и нужный тип node и настроил отображение необходимых полей (нужно добавить эти поля в индекс, чтобы иметь возможность фильтровать по ним).

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

    A/search_api_ranges.module +++ b/search_api_ranges.module @@ -144,11 +144,8 @@ function search_api_ranges_minmax($variables, $order = "ASC") { // otherwise our min/max would always equal user input. $filters = &$query->getFilter()->getFilters(); foreach ($filters as $key => $filter) { - - // Check for array: old style filters are objects which we can skip. - if (is_array($filter)) { - if ($filter == $variables["range_field"] || ($filter != $variables["range_field"] && $filter == "")) { - $current_filter = $filters[$key]; + if(isset($filter->tags) && is_array($filter->tags)){ + if(in_array("facet:".$variables["range_field"], $filter->tags)){ unset($filters[$key]); } }

    Патчим JQuery UI Slider: настраиваем редирект

    В версии модуля 7х-1.5 я столкнулся с тем, что если виджет слайдера расположен на странице, отличной от страницы поиска, то после изменения диапазона цены проиходило пере направление на текущую страницу, а не на страницу поиска.
    Ошибка кроется в функии search_api_ranges_block_slider_view_form_submit() (файл search_api_ranges.module, строка 364).
    Я не стал особо разбираться, что там и зачем, просто немного изменил код в строке 427:

    Drupal_goto($path, array("query" => array($params), "language" => $language)); + drupal_goto($values["path"], array("query" => array($params), "language" => $language));

    после чего проблема решилась.