Microcamtest

Лайфстайл портал

Фасетный индекс. 1С Битрикс. API

Умный фильтр, бизнес-логика сайта и перестроение фасетного индекса

Задача

Бизнес-логика не всегда логична и иногда не реализуема в рамках инструментария, предоставляемого продуктом, а порой заставляет искать довольно странные обходные пути.

Требуется вывести каталог товаров с установленными параметрами фильтрации:

  • Цена товара должна быть больше 0,
  • Показывать только товары у которых есть изображения,
  • Свойство “Показывать на сайте”, которое приходит из 1С должно быть в значении “Да”

Так же на странице со списком элементов требуется разместить компонент умного фильтра.

Решение

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

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

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

  • 1) Деактивировать товары, которые не попадают под условия бизнес-лигики отображения товаров на сайте.
  • 2) Перестроить фасетный индекс с учетом изменений активности товаров
  • 3) Повесить обработчик события “окончания синхронизации с 1С”, выполняющее пункты 1 и 2.

Деактивация товаров

Битрикс не предоставляет ф-ии для группового изменения элементов инфоблока. Есть метод CIBlockElement::Update, который может обновлять данные элементов по ID, для нашей задачи он не подходит, т.к. нам нужно деактивировать несколько тысяч товаров, а при работе этого метода дополнительно вызываются стандартные события Битрикса OnStartIBlockElementUpdate, OnAfterIBlockElementUpdate, что так же замедлит процесс деактивации.

Поэтому мы деактивируем товары прямым запросом к базе данных, используя возможности “нового” ядра D7

/** * Деактивация элементов инфоблок в соответствии с основным фильтром товаров * @param int $iblockId * @param array $arFilter * @return int */ function actualizeProducts($iblockId, $arFilter) { if(!\Bitrix\Main\Loader::includeModule(‘iblock’)) { return false; } $arFilterFinal = [ ‘IBLOCK_ID’ => $iblockId, $arFilter, ]; // получим список элементов для деактивации $dbRes = CIBlockElement::GetList([], $arFilterFinal, false, false, [‘ID’]); $arNotValidIds = []; while($arItem = $dbRes->getNext()) { $arNotValidIds[] = $arItem[‘ID’]; } $res = 0; if(count($arNotValidIds) > 0) { $strNotValidIds = implode(‘,’, $arNotValidIds); // формируем запрос на обновления флага активности товаров $sql = «UPDATE « . \Bitrix\Iblock\ElementTable::getTableName() . » SET ACTIVE = ‘N’ WHERE ID IN (« . $strNotValidIds . «)»; $connection = \Bitrix\Main\Application::getConnection(); $connection->queryExecute($sql); // запускаем переиндексацию фасета, это наша кастомная ф-я $res = reindexCatalogFaset($iblockId); } return $res; }

Пересчет фасетного индекса

/** * @param $iblockId * @return int */ function reindexCatalogFaset($iblockId) { $max_execution_time = 20; // Пересоздание фасетного индекса // Удалим имеющийся индекс Bitrix\Iblock\PropertyIndex\Manager::dropIfExists($iblockId); Bitrix\Iblock\PropertyIndex\Manager::markAsInvalid($iblockId); // Создадим новый индекс $index = Bitrix\Iblock\PropertyIndex\Manager::createIndexer($iblockId); $index->startIndex(); $NS = 0; do { $res = $index->continueIndex($max_execution_time); $NS += $res; } while($res > 0); $index->endIndex(); // чистим кэши \CBitrixComponent::clearComponentCache(«bitrix:catalog.smart.filter»); \CIBlock::clearIblockTagCache($iblockId); return $NS; }

Cron файл и добавление задания в crontab

Файлы для добавления в крон будем хранить в папке /local/crons/

создадим файл afterExch1C.php

<? $_SERVER[«DOCUMENT_ROOT»] = realpath(__DIR__ . ‘/../../’); require($_SERVER[«DOCUMENT_ROOT»].«/bitrix/modules/main/include/prolog_before.php»); $filePath = $_SERVER[«DOCUMENT_ROOT»] . ‘/’ . EXCH_1C_FILE_FLAG_NAME; if (!file_exists($filePath)) { return; } // сразу удалим файл, что бы не запуститься более 1ого раза unlink($filePath); $arFilter = CCommon::CATALOG_MAIN_FILTER_NOTVALID; echo «индекс пересоздан « . CCommon::actualizeProducts(IBID_CATALOG, $arFilter) . «\n«; ?>

Добавим задание в крон. Интервал выполнения проверки — каждые 5 минут.

Открываем файл заданий крона на изменение

crontab -e

Добавляем наше задание

*/5 * * * * <path_to_site>/local/crons/afterExch1C.php # на событие окончания обмена с 1С, выполняется КАЖДЫЕ 5 минут

Видео

Эффективность Elasticsearch

Какой же эффект дает использование Elasticsearch? Очень хороший – скорость загрузки страниц возрастает в несколько раз. Приведем несколько примеров роста производительности:

* значения указаны с учетом кэширования, без учета подгрузки javascript, картинок и т.д., без учета среднестатистических данных в период средней нагрузки на сайт

С ростом количества посетителей сайт ощущает себя вполне комфортно. Пиковое значение онлайн-пользователей за одну секунду, которое нам удалось получить во время одной из рассылок — около 500 человек. И при этом сайт работал быстро.

О проекте Kari

Kari — это российский обувной ритейлер, лидер в своем сегменте. Работает с 2012 года. Сегодня в сети Kari около 900 розничных торговых точек в четырех странах, а оборот в 2016 году составил более 30 млрд рублей.

Интернет-магазин kari.com работает под высокой нагрузкой:

  • около 100 тысяч визитов в день
  • несколько сотен одновременных соединений
  • более 70 тысяч товаров и 120 тысяч торговых предложений для каждой страны
  • более 30 сервисов
  • обмен с более чем 20 различными системами

Серверная архитектура kari.com

Наполнение товаров

Полноценное отображение товаров “из коробки” не работает

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

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

Фасетные индексы

Фасетный индекс предполагает создание индекса для каждой характеристики товаров, по которому можно делать очень быстрый поиск. В базу данных на каждый инфоблок добавляется две таблицы вида b_iblock_{IBLOCK_ID}_index и b_iblock_{IBLOCK_ID}_index_val в которых каждому продукту описываются характеристики, по которым его можно искать. В схеме выше эти две таблицы шли с индексом 34, т.к. для описания торговых предложений в взятой базе данных использовался 34-ый инфоблок. Таких блоков может быть много и соответственно на каждый инфоблок будет создана пара таблиц с фасетными индексами. Запись добавляется для каждой категории в ветви. Т.е. чтобы продукт искался по заданным полям во всех нужных категориях, нужно дублировать записи для каждой категории в которой вы хотите находить этот продукт. Как правило, это категория нижнего уровня — с продуктом, и все категории выше по этой ветви (все родители), чтобы например в категории верхнего уровня можно было найти продукты из подкатегорий.

Появление фасетных индексов было для нас неприятной неожиданностью. После одного из зимних обновлений товары во фронтэнде пропали. Никаких ошибок. Всё видно в панели администрирования. Но во фронтэнде новых товаров не было. Сквозь образовавшуюся тишину было слышно, как седеют программисты. Оказалось, что отныне и навсегда продукты, для которых не заполнены фасетные индексы, не отображаются. Даже если эти самые фасетные индексы никто не хотел, никто не включал намеренно и более того никто ничего не выбирал во фронтэнде. Т.е. фильтр почему-то работает даже если поля для фильтрации пользователем не заполнены. Поведение странное. Последствия таких внедрений — у людей умирали магазины. Люди несли убытки. Независимо от способа наполнения.

Отдельно стоит упомянуть про вычисление идентификатора характеристики. Вы верите в магию? Вот это и есть магия. Во-первых, согласно документации это поле должно не соответствовать идентификатору из общего списка характеристик (что было бы логично для фильтра по характеристикам), а являться идентификатором из общего списка характеристик умноженным на два. Внятного ответа на вопрос “В чём смысл этой магии” мы так и не нашли. Кажется, умножение на 42 работало бы гораздо лучше, в нём есть хоть какой-то смысл. Во-вторых, неоднократно замечалось, что наполнение сайта через админку могло не соблюдать эту, казалось бы, тривиальную магию.

Теги