כאשר רכיב ה-bitrix:catalog.recommended הסטנדרטי בחנות מקוונת מציג את אותם מוצרים לכל המבקרים, ההמרה של בלוק ההמלצות יורדת ב-30–60%. המשתמש רואה פריטים שכבר קנה או צפה בהם, ועוזב למתחרה עם בלוק מדויק של "לקוחות קנו גם". אנחנו, צוות עם ניסיון של 10+ שנים ולמעלה מ-50 הטמעות ב-1C-Bitrix, בנינו מערכת המלצות מותאמת אישית המבוססת על התנהגות — ללא ML, רק PHP + SQL. מוכן תוך 2–5 ימים. קבלו ייעוץ לפרויקט שלכם — נעריך את האפשרויות בחינם.
אילו בעיות אנחנו פותרים?
רכיב ה-b_user_behavior הסטנדרטי אינו משתמש בהתנהגות המשתמש. הוא מציע את אותו הדבר לכולם. אנו מיישמים אותות התנהגותיים: צפיות, רכישות, עגלה. טעויות נפוצות — התעלמות ממשקל האירוע (רכישה חשובה פי 10 מצפייה) וחוסר בהגברת קטגוריה אישית. הפתרון שלנו מתקן בעיות אלה, ומעלה את שיעור הקליקים (CTR) של ההמלצות ב-30–60%. בפרויקט אחד עם קטלוג של 15,000 מוצרים, העלינו את ההמרה של בלוק ההמלצות מ-1.2% ל-3.8% תוך שבוע.
כיצד פועלות המלצות מבוססות התנהגות
אנו אוספים אירועים בטבלת $weights = [ 'purchase' => 10, 'cart_add' => 5, 'favorite_add' => 4, 'view_long' => 2, 'view_short' => 1, 'search_click' => 3, ]; . מקצים משקלים:
| אירוע | משקל |
|---|---|
| רכישת מוצר | 10 |
| הוספה לעגלה | 5 |
| הוספה למועדפים | 4 |
| צפייה בכרטיס מוצר (>30 שניות) | 2 |
| צפייה בכרטיס מוצר (<30 שניות) | 1 |
| שאילתת חיפוש עם קליק | 3 |
המשקלים מאוחסנים בתצורה — קל להתאים אותם לעסק שלכם. חלון הניתוח — 60 יום (ניתן להגדרה).
דוגמה לתצורת משקלים ב-PHP
$weights = [ 'purchase' => 10, 'cart_add' => 5, 'favorite_add' => 4, 'view_long' => 2, 'view_short' => 1, 'search_click' => 3, ]; למה סינון שיתופי מבוסס פריטים?
זוהי נקודת האיזון בין מוצרים אקראיים ל-ML. הרעיון פשוט: "מי שצפה במוצר A צפה גם ב-B, C, D." אנו מחשבים זאת ישירות מהמסד נתונים. סינון מבוסס פריטים נותן המלצות מדויקות פי 3–5 בהשוואה למוצרים פופולריים. הוא אינו דורש שרת ML נפרד וניתן להרחבה בקלות.
השוואת גישות:
| גישה | רלוונטיות | מורכבות | תשתית |
|---|---|---|---|
| ללא התאמה אישית | נמוכה | נמוכה | לא נדרשת |
| מבוסס פריטים (שלנו) | בינונית | בינונית | PHP + SQL בלבד |
| מודל ML | גבוהה | גבוהה | Python + שרת |
שאילתה אופטימלית למציאת מוצרים קשורים:
SELECT b2.ENTITY_ID AS recommended_id, COUNT(DISTINCT b2.USER_ID) AS co_view_count FROM b_user_behavior b1 JOIN b_user_behavior b2 ON b1.USER_ID = b2.USER_ID AND b1.ENTITY_ID != b2.ENTITY_ID AND b2.EVENT_TYPE IN ('view', 'cart_add', 'purchase') AND b2.DATE_CREATE > NOW() - INTERVAL '60 days' WHERE b1.ENTITY_ID = :current_item_id AND b1.EVENT_TYPE IN ('view', 'cart_add', 'purchase') GROUP BY b2.ENTITY_ID ORDER BY co_view_count DESC LIMIT 20; שאילתה זו רצה פעם בשעה באמצעות סוכן Bitrix. אנו שומרים את התוצאה במטמון בטבלה נפרדת:
CREATE TABLE b_item_recommendations ( ITEM_ID INT NOT NULL, RECOMMENDED_ID INT NOT NULL, SCORE FLOAT NOT NULL, UPDATED_AT TIMESTAMP DEFAULT NOW(), PRIMARY KEY (ITEM_ID, RECOMMENDED_ID) ); CREATE INDEX idx_item_recs_item ON b_item_recommendations(ITEM_ID, SCORE DESC); ניקוד אישי ובחירת מועמדים
מתוך 20 המועמדים, אנו מיישמים הגברה לפי הקטגוריות המועדפות על המשתמש:
function getPersonalizedRecs(int $itemId, int $userId, int $limit = 8): array { // 1. Получить кандидатов из item-based таблицы $candidates = getCandidates($itemId, 20); if (empty($candidates) || !$userId) { return array_slice($candidates, 0, $limit); } // 2. Получить категории из истории пользователя $userCategoryIds = getUserTopCategories($userId, 10); // 3. Boosting: поднять товары из предпочитаемых категорий foreach ($candidates as &$candidate) { $sectionId = getElementSectionId($candidate['id']); if (in_array($sectionId, $userCategoryIds)) { $candidate['score'] *= 1.5; } } // 4. Убрать уже купленные товары $purchased = getUserPurchasedIds($userId); $candidates = array_filter($candidates, fn($c) => !in_array($c['id'], $purchased) ); usort($candidates, fn($a, $b) => $b['score'] <=> $a['score']); return array_column(array_slice($candidates, 0, $limit), 'id'); } מטמון ותצוגה
רכיב מותאם אישית SELECT b2.ENTITY_ID AS recommended_id, COUNT(DISTINCT b2.USER_ID) AS co_view_count FROM b_user_behavior b1 JOIN b_user_behavior b2 ON b1.USER_ID = b2.USER_ID AND b1.ENTITY_ID != b2.ENTITY_ID AND b2.EVENT_TYPE IN ('view', 'cart_add', 'purchase') AND b2.DATE_CREATE > NOW() - INTERVAL '60 days' WHERE b1.ENTITY_ID = :current_item_id AND b1.EVENT_TYPE IN ('view', 'cart_add', 'purchase') GROUP BY b2.ENTITY_ID ORDER BY co_view_count DESC LIMIT 20; מקבל CREATE TABLE b_item_recommendations ( ITEM_ID INT NOT NULL, RECOMMENDED_ID INT NOT NULL, SCORE FLOAT NOT NULL, UPDATED_AT TIMESTAMP DEFAULT NOW(), PRIMARY KEY (ITEM_ID, RECOMMENDED_ID) ); CREATE INDEX idx_item_recs_item ON b_item_recommendations(ITEM_ID, SCORE DESC); . הבלוק הראשי נשמר במטמון לפי function getPersonalizedRecs(int $itemId, int $userId, int $limit = 8): array { // 1. Получить кандидатов из item-based таблицы $candidates = getCandidates($itemId, 20); if (empty($candidates) || !$userId) { return array_slice($candidates, 0, $limit); } // 2. Получить категории из истории пользователя $userCategoryIds = getUserTopCategories($userId, 10); // 3. Boosting: поднять товары из предпочитаемых категорий foreach ($candidates as &$candidate) { $sectionId = getElementSectionId($candidate['id']); if (in_array($sectionId, $userCategoryIds)) { $candidate['score'] *= 1.5; } } // 4. Убрать уже купленные товары $purchased = getUserPurchasedIds($userId); $candidates = array_filter($candidates, fn($c) => !in_array($c['id'], $purchased) ); usort($candidates, fn($a, $b) => $b['score'] <=> $a['score']); return array_column(array_slice($candidates, 0, $limit), 'id'); } — אותם מועמדים לכולם. הגברה אישית מוחלת באמצעות בקשת AJAX נפרדת לאחר טעינת העמוד. זה נותן מהירות גבוהה: מטמון ברמת Bitrix, SQL מינימלי בעת רינדור. תיעוד מטמון של 1C-Bitrix.
העברת היסטוריה לאחר התחברות
Bitrix אינו מעביר אוטומטית היסטוריית התנהגות אנונימית למשתמש מחובר. אנו מוסיפים מטפל local:catalog.recommendations:
AddEventHandler('main', 'OnAfterUserLogin', function($fields) { $fuserId = \CSaleUser::GetAnonymousUserID(); if (!$fuserId) return; $DB->Query(" UPDATE b_user_behavior SET USER_ID = " . (int)$fields['USER_ID'] . " WHERE SESSION_ID = '" . $DB->ForSql(session_id()) . "' AND USER_ID IS NULL "); }); ניטור יעילות ההמלצות
מדד מפתח: שיעור הקליקים (CTR) של בלוק ההמלצות — יחס קליקים להופעות. קו בסיס ללא התאמה אישית: 0.5–1.5%. לאחר מעבר למבוסס פריטים עם הגברה אישית: 2.5–4.0%. עקבו באמצעות אירועי רכישה ומונה קליקים מותאם אישית ב-localStorage או דרך יעדי Yandex.Metrica.
מדדים נוספים: המרה של מוצר מומלץ לרכישה, ערך סל ממוצע להזמנות עם המלצות לעומת בלעדיהן, שיעור חזרת משתמשים עם קליקים חוזרים על הבלוק. נתונים אלה עוזרים לכוונן באופן קבוע את משקלי האירועים ואת חלון הניתוח למאפייני הקטלוג הספציפי.
מדי רבעון אנו בוחנים את תצורת המשקלים: אם חלקם של צפיות קצרות גדל, אנו מפחיתים את משקלן. אם רכישות מתרכזות בקטגוריה צרה, אנו מוסיפים הגברה עונתית לפי דגלי מוצר.
מה כלול בעבודה
- ביקורת על הקטלוג הנוכחי ומקורות נתוני ההתנהגות.
- עיצוב סכמת
ELEMENT_IDותצורת משקלים. - פיתוח שאילתות SQL לסינון מבוסס פריטים ולוגיקת PHP להגברה אישית.
- אינטגרציה של רכיב ההמלצות ומטפל AJAX.
- בדיקות על משתמשים אמיתיים עם מדידת CTR.
- תיעוד על תצורת משקלים ותמיכה.
- הכשרת הצוות שלכם לעבודה עם המערכת.
- אחריות ל-30 יום לתפעול תקין לאחר המסירה.
לוחות זמנים ואחריות
לוח זמנים משוער: 2 עד 5 ימי עסקים בהתאם למורכבות הקטלוג. חיסכון בזמן בהשוואה לפיתוח מאפס: עד 40%. אנו מספקים אחריות לתפעול תקין של ההמלצות למשך 30 יום לאחר המסירה. הזמינו ביקורת חינם של הקטלוג שלכם — נעריך את האפשרויות.







