Разработка блока "похожие товары" 1С-Битрикс
«Похожие товары» — блок для тех случаев, когда текущий товар не подходит покупателю: другой цвет, другой размер, другой производитель. Или нет в наличии. Задача блока — удержать пользователя в каталоге и предложить альтернативу, а не отпустить его на другой сайт.
Критерии похожести
«Похожий» — понятие, которое нужно определить для каждого проекта. Возможные критерии:
- Та же категория — базовый уровень.
- Те же характеристики — для технических товаров (электроника, стройматериалы): мощность, материал, тип.
- Близкая цена — покупатель с бюджетом редко переходит в другую ценовую категорию.
- Тот же бренд — работает для брендозависимых покупок (косметика, одежда).
- Схожие теги — если в каталоге есть теговая структура.
Система похожести строится как взвешенная сумма совпадений по выбранным критериям.
Алгоритм расчёта схожести
function calculateSimilarityScore(int $productId, int $candidateId): float {
$product = getProductData($productId);
$candidate = getProductData($candidateId);
$score = 0.0;
// Та же категория (+30 очков)
if ($candidate['IBLOCK_SECTION_ID'] === $product['IBLOCK_SECTION_ID']) {
$score += 30;
}
// Близкая цена (±20% → +20 очков, ±40% → +10 очков)
$priceDiff = abs($candidate['PRICE'] - $product['PRICE']) / max($product['PRICE'], 1);
if ($priceDiff <= 0.2) $score += 20;
elseif ($priceDiff <= 0.4) $score += 10;
// Совпадение бренда (+25 очков)
if ($candidate['PROP_BRAND'] && $candidate['PROP_BRAND'] === $product['PROP_BRAND']) {
$score += 25;
}
// Совпадения по характеристикам (до +25 очков)
$specKeys = ['PROP_MATERIAL', 'PROP_COLOR', 'PROP_SIZE_TYPE'];
$specScore = 0;
foreach ($specKeys as $key) {
if (isset($product[$key], $candidate[$key]) && $product[$key] === $candidate[$key]) {
$specScore += 8;
}
}
$score += min($specScore, 25);
return $score;
}
Предварительный расчёт для каталогов с тысячами товаров
Рассчитывать схожесть «на лету» для каталога в 10 000+ товаров невозможно. Предрасчёт:
CREATE TABLE custom_similar_products (
product_id INT NOT NULL,
similar_id INT NOT NULL,
score FLOAT NOT NULL,
calculated_at DATETIME DEFAULT NOW(),
PRIMARY KEY (product_id, similar_id),
INDEX idx_product (product_id, score DESC)
);
Агент считает схожесть внутри каждой категории:
function RecalcSimilarProductsAgent(): string {
static $sectionOffset = 0;
$sections = getSectionsBatch($sectionOffset, 10);
if (empty($sections)) {
$sectionOffset = 0; // начать сначала при следующем запуске
return 'RecalcSimilarProductsAgent();';
}
foreach ($sections as $section) {
$products = getProductsBySection($section['ID']);
foreach ($products as $p) {
$scores = [];
foreach ($products as $candidate) {
if ($candidate['ID'] === $p['ID']) continue;
$scores[$candidate['ID']] = calculateSimilarityScore($p['ID'], $candidate['ID']);
}
arsort($scores);
$top = array_slice($scores, 0, 20, true);
saveSimilarProducts($p['ID'], $top);
}
}
$sectionOffset += 10;
return 'RecalcSimilarProductsAgent();';
}
Агент запускается каждую ночь; обрабатывает по 10 разделов за запуск.
Компонент с учётом наличия
Перед отображением отфильтровываем товары без остатка:
$similarIds = getSimilarFromTable($productId, 20); // запас с учётом фильтрации
$filter = [
'ID' => $similarIds,
'ACTIVE' => 'Y',
'!ID' => $productId,
];
// Если в настройках: показывать только товары в наличии
if ($arParams['ONLY_AVAILABLE'] === 'Y') {
$filter['>CATALOG_QUANTITY'] = 0;
}
$res = \CIBlockElement::GetList(
[],
$filter,
false,
['nPageSize' => (int)$arParams['LIMIT']],
['ID', 'NAME', 'DETAIL_PAGE_URL', 'PREVIEW_PICTURE', 'CATALOG_PRICE_1']
);
Ручное управление похожестью
Для случаев, когда алгоритм не справляется (специфические товары, нестандартные связи) — добавляем инструмент ручного управления в административной части. Менеджер открывает товар → вкладка «Похожие товары» → мультивыбор из каталога. Ручные связи имеют приоритет над автоматическими.
-- Ручные связи хранятся отдельно, не перезаписываются агентом
CREATE TABLE custom_similar_manual (
product_id INT NOT NULL,
similar_id INT NOT NULL,
sort INT DEFAULT 500,
created_by INT,
created_at DATETIME DEFAULT NOW(),
PRIMARY KEY (product_id, similar_id)
);
Логика отображения
Итоговая выборка для блока: сначала ручные связи (в порядке sort), затем автоматические по score. Если суммарно меньше нужного числа — fallback к товарам той же категории.
Разница с «С этим товаром покупают»
| Критерий | Похожие товары | С этим покупают |
|---|---|---|
| Основа | Свойства товара | История заказов |
| Новые товары | Работает сразу | Нужна история покупок |
| Логика | Альтернатива | Дополнение |
| Место на сайте | Карточка товара | Карточка товара, корзина |
| Влияет на | Удержание пользователя | Средний чек |
Сроки
| Этап | Срок |
|---|---|
| Определение критериев схожести для каталога | 1 день |
| Алгоритм расчёта score + таблица | 2–3 дня |
| Агент предрасчёта | 1–2 дня |
| Компонент с фильтрацией и fallback | 2–3 дня |
| Ручное управление в админке | 1–2 дня |
| Тестирование | 1–2 дня |
Итого: 1–1.5 недели.







