Рекомендации товаров по истории покупок в 1С-Битрикс

Мы внедряем персонализированные рекомендации на основе истории покупок в 1С-Битрикс. Типичная конверсия в повторные продажи — менее 5%. После внедрения нашего подхода показатель вырастает до 20–30%. При этом не требуется подключать внешние ML-сервисы — вся логика реализуется на SQL и PHP силами само
Услуги, которые мы предлагаем
Показано 1 из 1Все 1626 услуг
Рекомендации товаров по истории покупок в 1С-Битрикс
Простой
~1 день

Наши компетенции:

Часто задаваемые вопросы

Последние работы

  • image_website-b2b-advance_0.webp
    Разработка сайта компании B2B ADVANCE
    1460
  • image_bitrix-bitrix-24-1c_fixper_448_0.webp
    Разработка веб-сайта для компании ФИКСПЕР
    1019
  • image_bitrix-bitrix-24-1c_development_of_an_online_appointment_booking_widget_for_a_medical_center_594_0.webp
    Разработка на базе Битрикс, Битрикс24, 1С для компании Development of an Online Appointment Booking Widget for a Medical Center
    761
  • image_bitrix-bitrix-24-1c_mirsanbel_458_0.webp
    Разработка на базе 1С Предприятие для компании МИРСАНБЕЛ
    882
  • image_crm_dolbimby_434_0.webp
    Разработка сайта на CRM Битрикс24 для компании DOLBIMBY
    809
  • image_crm_technotorgcomplex_453_0.webp
    Разработка на базе Битрикс24 для компании ТЕХНОТОРГКОМПЛЕКС
    1163

Мы внедряем персонализированные рекомендации на основе истории покупок в 1С-Битрикс. Типичная конверсия в повторные продажи — менее 5%. После внедрения нашего подхода показатель вырастает до 20–30%. При этом не требуется подключать внешние ML-сервисы — вся логика реализуется на SQL и PHP силами самого Битрикса, что даёт полный контроль и снижает затраты на внешние подписки.

Большая часть рекомендаций — item-based («с этим товаром часто покупают») и user-based («ваши прошлые покупки похожи на покупки других»). Оба паттерна используют стандартные таблицы Битрикса и оптимизируются индексами. Без правильного индексирования JOIN на таблице b_sale_order_basket в магазине с 500 000 заказов выполняется 30+ секунд; с составным индексом (PRODUCT_ID, ORDER_ID) запрос укладывается в 0,1 секунды. Внутренняя реализация окупается в течение нескольких месяцев за счёт отсутствия ежемесячной платы за ML-сервисы и снижения нагрузки на сервер.

Два основных паттерна рекомендаций

Item-based: «с этим товаром часто покупают». Анализируем совместную встречаемость товаров в заказах. User-based: «ваши прошлые покупки похожи на покупки пользователей X, они взяли ещё Y». Оба паттерна строятся на данных из стандартных таблиц Битрикса.

Таблицы с данными о покупках

Вся история заказов в Битриксе — три ключевые таблицы:

  • b_sale_order — заказы: поля USER_ID, CANCELED, STATUS_ID, PRICE
  • b_sale_order_basket — состав заказов: ORDER_ID, PRODUCT_ID, QUANTITY, PRICE
  • b_catalog_product — наличие товара: QUANTITY, AVAILABLE

Для рекомендаций используем только незаменённые заказы (CANCELED = 'N') в финальных статусах. Статус F (Finished) — стандартный финальный, но на многих проектах используются кастомные статусы.

Item-based: «с этим часто покупают»

Основной паттерн — блок «Вместе с этим товаром покупают» на карточке товара:

SELECT ob2.PRODUCT_ID, COUNT(DISTINCT ob1.ORDER_ID) AS co_purchase_count, SUM(ob2.QUANTITY) AS total_qty FROM b_sale_order_basket ob1 JOIN b_sale_order_basket ob2 ON ob1.ORDER_ID = ob2.ORDER_ID AND ob2.PRODUCT_ID != ob1.PRODUCT_ID JOIN b_sale_order o ON o.ID = ob1.ORDER_ID AND o.CANCELED = 'N' AND o.DATE_INSERT > NOW() - INTERVAL '90 days' WHERE ob1.PRODUCT_ID = :target_product_id GROUP BY ob2.PRODUCT_ID ORDER BY co_purchase_count DESC LIMIT 20; 

Этот запрос выполняется офлайн через агент Битрикса — раз в 4 часа. Результат пишется в таблицу:

CREATE TABLE b_product_cross_sell ( SOURCE_ID INT NOT NULL, RECOMMENDED_ID INT NOT NULL, SCORE INT NOT NULL, UPDATED_AT TIMESTAMP DEFAULT NOW(), PRIMARY KEY (SOURCE_ID, RECOMMENDED_ID) ); CREATE INDEX idx_cross_sell_source ON b_product_cross_sell(SOURCE_ID, SCORE DESC); 

Индекс (PRODUCT_ID, ORDER_ID) на b_sale_order_basket критически важен — без него JOIN на больших магазинах (100k+ заказов) будет выполняться секундами.

User-based: персональные рекомендации для авторизованного пользователя

Для конкретного пользователя строится список товаров, которые купили «похожие» покупатели. «Похожесть» — пересечение истории покупок.

function getUserBasedRecs(int $userId, int $limit = 8): array { // 1. История покупок текущего пользователя $myOrderIds = array_column( \Bitrix\Sale\OrderTable::getList([ 'filter' => ['USER_ID' => $userId, 'CANCELED' => 'N'], 'select' => ['ID'], ])->fetchAll(), 'ID' ); if (empty($myOrderIds)) return getPopularItems($limit); $myProductIds = array_column( \Bitrix\Sale\Internals\BasketTable::getList([ 'filter' => ['ORDER_ID' => $myOrderIds], 'select' => ['PRODUCT_ID'], ])->fetchAll(), 'PRODUCT_ID' ); // 2. Пользователи, купившие те же товары // 3. Товары этих пользователей, которых у нас нет $res = $GLOBALS['DB']->Query(" SELECT ob2.PRODUCT_ID, COUNT(DISTINCT o2.USER_ID) AS score FROM b_sale_order_basket ob1 JOIN b_sale_order o1 ON o1.ID = ob1.ORDER_ID AND o1.USER_ID = {$userId} JOIN b_sale_order_basket ob2 ON ob2.ORDER_ID IN ( SELECT DISTINCT o3.ID FROM b_sale_order o3 JOIN b_sale_order_basket ob3 ON ob3.ORDER_ID = o3.ID AND ob3.PRODUCT_ID IN (" . implode(',', array_map('intval', $myProductIds)) . ") WHERE o3.USER_ID != {$userId} AND o3.CANCELED = 'N' ) WHERE ob2.PRODUCT_ID NOT IN (" . implode(',', array_map('intval', $myProductIds)) . ") GROUP BY ob2.PRODUCT_ID ORDER BY score DESC LIMIT {$limit} "); $ids = []; while ($row = $res->Fetch()) $ids[] = (int)$row['PRODUCT_ID']; return $ids; } 

Фильтрация рекомендованных товаров

Рекомендованные ID передаются в финальный фильтр перед отображением — убрать неактивные, снятые с продажи, с нулевым остатком:

$availableIds = \CIBlockElement::GetList( ['SORT' => 'ASC'], [ 'ID' => $recommendedIds, 'ACTIVE' => 'Y', 'IBLOCK_ID' => CATALOG_IBLOCK_ID, '>CATALOG_QUANTITY' => 0, ], false, ['nTopCount' => 8], ['ID'] )->fetchAll(); 

Кеш и инвалидация

Кеш item-based рекомендаций: по PRODUCT_ID, TTL = 4 часа (синхронно с агентом обновления). Кеш user-based: по USER_ID, TTL = 30 минут — короче, потому что история пользователя меняется. Инвалидация: при сохранении нового заказа (OnSaleOrderSaved) сбрасывать кеш для всех товаров из заказа через тег product_recs_{id}.

Преимущества внутренней реализации перед внешними ML-сервисами

Готовые сервисы (Recombee, Nosto) требуют ежемесячной оплаты и интеграции REST API. Внутренняя реализация на Битриксе:

  • не требует внешних зависимостей,
  • работает быстрее, так как данные уже в БД,
  • даёт полный контроль над алгоритмом,
  • легко модифицируется под специфику каталога.
Параметр Item-based User-based
Принцип «с этим товаром часто берут» «люди с похожей историей купили»
Данные Совместные покупки в заказах Пересечение пользовательских корзин
Обновление Раз в 4 часа агент Онлайн при запросе (кеш 30 мин)
Когда эффективен Товар имеет связанные позиции У пользователя есть история покупок

Типичные проблемы с производительностью и их решения

Проблема Причина Решение
JOIN выполняется минуты Отсутствует индекс (PRODUCT_ID, ORDER_ID) на b_sale_order_basket Создать составной индекс
Кеш устаревает некорректно Нет инвалидации по событию Добавить обработчик OnSaleOrderSaved с тегированной очисткой
User-based медленный для новых пользователей Отсутствие истории Использовать item-based или популярные товары как fallback

Почему индекс (PRODUCT_ID, ORDER_ID) критичен?

Без этого составного индекса JOIN по b_sale_order_basket в магазине с 100 000 заказов выполняется 10–30 секунд. Софтверные решения вроде временных таблиц не экономят ресурсы. Индекс сокращает время до 0,05–0,1 секунды, что критично для агента, выполняющегося раз в 4 часа.

Как обеспечивается актуальность рекомендаций?

Item-based пересчитываются раз в 4 часа, user-based — при каждом запросе с кешем на 30 минут. Дополнительно при создании нового заказа сбрасывается кеш для затронутых товаров. Это гарантирует, что пользователь видит свежие рекомендации, а нагрузка на сервер остаётся низкой.

Что входит в нашу работу

  • Аудит текущей структуры данных и нагрузок на БД.
  • Реализация агентов расчёта item-based и user-based.
  • Создание таблицы b_product_cross_sell и необходимых индексов.
  • Интеграция фильтрации по активности и остаткам.
  • Настройка тегированного кеширования и инвалидации по событиям.
  • Документация по архитектуре и инструкция по деплою.
  • Обучение вашего разработчика поддержке.

Сроки и стоимость

Срок реализации — от 3 до 7 рабочих дней в зависимости от сложности каталога и объёма данных. Точная стоимость рассчитывается после аудита — закажите аудит, и мы оценим проект бесплатно.

Опираясь на опыт десятка внедрений в магазинах с товарооборотом от $450k–650k, гарантируем стабильную работу без просадок производительности. Свяжитесь с нами — проведём аудит вашего каталога и рассчитаем точную стоимость. Получите персонализированные рекомендации уже сегодня.