בדוגמה הזו אפשר לראות איך משתמשים במאפייני מעבר כדי לתעדף מסלולים שבהם אותה מכונית מבצעת איסופים ומסירות בקרבת מקום בפרק זמן אחד. מידע נוסף על מאפייני מעבר זמין במאמר Model Business Logic with Transition Attributes.
בדוגמה הזו:
- משלוחים A, B ו-C קרובים זה לזה באותו רחוב.
- משלוחים נוספים יגיעו בהמשך.
- אין זמני אספקה ספציפיים למשלוחים.
- לא משנה מה לוח הזמנים של הביקורים, הרכב צריך לנסוע בכביש הזה פעמיים: פעם אחת בבוקר בדרך מהמחסן, ופעם אחת בערב בדרך חזרה.
- מרחק הנסיעה הכולל ומשך המסלול תמיד זהים, לא משנה מתי מבצעים את A, B ו-C.

במצב כזה, ובמקרה של בקשה שמשתמשת רק בעלות לשעה ובעלות לקילומטר, יכול להיות שהמסלול האופטימלי יכלול את נקודות A ו-B בבוקר ואת נקודה C בערב, והעלות של הפתרון תהיה זהה לעלות שהייתה מתקבלת אם כל שלוש הנקודות היו מטופלות בו-זמנית.
עלות לקילומטר עם סף
כדי לקבץ ביקורים קרובים, קודם צריך לבחור מרחק סף. זהו המרחק המקסימלי בין שני ביקורים שאתם מחשיבים כקרובים. בדוגמה הזו נעשה שימוש בסף של 100 מטרים, שמתאים בערך לבלוק אחד באזור עירוני. אתם יכולים להגדיל או להקטין את הסף בהתאם לצרכים של העסק ולהעדפות של הנהגים.
כדי לקבץ ביקורים סמוכים במרחק של עד 100 מטרים זה מזה, מגדירים עלות גבוהה ל-100 המטרים הראשונים של כל מעבר ועלות נמוכה יותר לכל מטר נוסף של המעבר. מכיוון ש-100 המטרים הראשונים הם היקרים ביותר, הכלי לאופטימיזציה חוסך הכי הרבה כסף על ידי שימוש במעברים קצרים יותר מסף 100 המטרים, גם אם זה אומר להאריך את המסלול הכולל.
כדי להגדיר את העלויות, מוסיפים רשומה חדשה ל-ShipmentModel.transition_attributes עם המאפיינים הבאים:
- כדי להתאים את כל המעברים האפשריים, בוחרים תג שלא נמצא בשימוש בשום מקום במודל, למשל
UNUSED_TAG. מגדירים את התג הזה ל-SetTransitionAttributes.excluded_src_tagandTransitionAttributes.excluded_dst_tag. - מגדירים את
TransitionAttributes.distance_limitעם מרחק הסף והעלויות:- מגדירים את
DistanceLimit.soft_max_metersלערך הסף שנבחר. - מגדירים את
DistanceLimit.cost_per_kilometer_below_soft_maxלעלות לקילומטר מתחת לסף. - מגדירים את
DistanceLimit.cost_per_kilometer_above_soft_maxלעלות לקילומטר מעל הסף.
- מגדירים את
{
"model": {
"transitionAttributes": [
{
"excluded_dst_tag": "UNUSED_TAG",
"excluded_src_tag": "UNUSED_TAG",
"distanceLimit": {
"softMaxMeters": 100,
"costPerKilometerBelowSoftMax": 50,
"costPerKilometerAboveSoftMax": 1,
}
}
]
}
}
אסור להשתמש בתג #unused_tag# באף משלוח או רכב כדי להתאים לכל המעברים האפשריים. מידע נוסף זמין במאמר איך להתאים את כל בקשות הביקור.
איך פועלת ההתראה "עלות גבוהה מתחת לסף"
בקטע הזה אפשר לראות איך העלות מתחת לסף ומעליו משפיעה על העלות הכוללת של פתרונות שונים בתרחיש לדוגמה.
פתרון 1: מבצעים את הפעולות A ו-B בדרך לשם, ואת הפעולה C בדרך חזרה
בפתרון הזה, המשלוחים מחולקים לשני מעברים בכביש הזה. שניים מהם נשלחים במעבר הראשון, והשלישי נשלח במעבר השני. יש 5 מעברים:
| מעבר | מרחק | מתחת לסף | מעל הסף | ||
|---|---|---|---|---|---|
| מרחק | עלות | מרחק | עלות | ||
| מחסן →A | 1,000 מטרים | 100 מ' | 5 | 900 מטרים | 0.9 |
| א←ב | 50 מטר | 50 מטר | 2.5 | 0 מטרים | 0 |
| B→other | 1,030 מ' | 100 מ' | 5 | 930 מ' | 0.93 |
| other→C | 1,000 מ' | 100 מ' | 5 | 900 מטרים | 0.9 |
| C→depot | 1,080 מ' | 100 מטר | 5 | 980 מ' | 0.98 |
| סה"כ | 450 מ' | 22.5 | 3710 מ' | 3.71 | |
העלות הכוללת מחושבת כסכום של שתי העלויות לקילומטר:
- העלות לקילומטר מתחת לסף (50) כפול מרחק הנסיעה הכולל מתחת לסף (450 מטרים = 0.45 ק"מ),
- העלות לקילומטר מעל הסף (1) כפול המרחק הכולל מעל הסף (3,710 מטרים = 3.71 ק"מ).
העלות הכוללת היא 0.45 * 50 + 3.71 * 1 = 22.5 + 3.71 = 26.21.
פתרון 2: מבצעים את הפעולות א', ב' ו-ג' בדרך לשם, ולא מבצעים שום פעולה בדרך חזרה
בפתרון הזה, בניגוד לפתרון 1, כל שלושת המשלוחים נמסרים "כקבוצה" במהלך נסיעה אחת בכביש. במעבר השני, הרכב לא עוצר בכלל. שוב, יש 5 מעברים, אבל האורך וההרכב שלהם שונים:
| מעבר | מרחק | מתחת לסף | מעל הסף | ||
|---|---|---|---|---|---|
| מרחק | עלות | מרחק | עלות | ||
| מחסן →A | 1,000 מטרים | 100 מ' | 5 | 900 מטרים | 0.9 |
| א←ב | 50 מטר | 50 מטר | 2.5 | 0 מטרים | 0 |
| B→C | 30 דקות | 30 דקות | 1.5 | 0 מטרים | 0 |
| C→אחר | 1,000 מטרים | 100 מ' | 5 | 900 מטרים | 0.9 |
| other→depot | 2,080 מ' | 100 מ' | 5 | 1,980 מ' | 1.98 |
| סה"כ | 380 מטר | 19 | 3,780 מ' | 3.78 | |
באמצעות אותו חישוב כמו בפתרון 1, העלות הכוללת היא 0.38 * 50 + 3.78 * 1 = 19 + 3.78 = 22.78, וביצוע כל הביקורים בבלוק זמן אחד הוא זול יותר מביצועם בשתי קבוצות. כדי לחזק את ההשפעה הזו, אפשר להגדיל את DistanceLimit.cost_per_kilometer_below_soft_max.
למה עלות נמוכה לקילומטר מתחת לסף לא עובדת
מכיוון שאתם רוצים להעדיף מעברים קצרים על פני מעברים ארוכים, יכול להיות שתתפתו לתת עלות גבוהה לקילומטר למעברים ארוכים, ולשמור על עלות נמוכה לקילומטר למעברים קצרים. אבל בפועל, יש לזה השפעה הפוכה: מכיוון ש-100 המטרים הראשונים של המעבר הם הזולים ביותר, כלי האופטימיזציה משתמש במטרים ה "זולים" האלה בצורה היעילה ביותר על ידי העדפת מעברים שקרובים ל-100 מטרים או יותר.
אפשר לראות את ההשפעה הזו בשני הפתרונות לדוגמה. אם מחליפים את העלות לקילומטר מתחת לסף ומעליו, העלויות של המסלול משתנות:
| עלות גבוהה מעל הסף | עלות גבוהה מתחת לסף | |||
|---|---|---|---|---|
| פתרון 1 | פתרון 2 | פתרון 1 | פתרון 2 | |
| מספר הקילומטרים מתחת לסף | 0.45 | 0.38 | 0.45 | 0.38 |
| עלות לכל קילומטר מתחת לסף | 1.00 | 1.00 | 50.00 | 50.00 |
| ק"מ מעל הסף | 3.71 | 3.78 | 3.71 | 3.78 |
| עלות לכל ק"מ מעל הסף | 50.00 | 50.00 | 1.00 | 1.00 |
| עלות כוללת | 185.95 | 189.38 | 26.21 | 22.78 |
בכל גרסה, העלות הכוללת הנמוכה מבין שתי העלויות של הפתרונות מודגשת. אפשר לראות שכאשר משתמשים בעלות גבוהה מעל הסף, העלות הכוללת של המסלול גבוהה יותר במסלול שבו הביקורים מקובצים, וזה ההפך ממה שרציתם להשיג.