يوضّح هذا الدليل كيف يمكن أن يختلف عدد المركبات المقدَّمة في حلّ Route Optimization استنادًا إلى مَعلمات الطلب.
لا تعمل واجهة برمجة التطبيقات Route Optimization API على تحسين ترتيب إكمال الشحنات فحسب، بل إنّها تُعيّن أيضًا هذه الشحنات للمركبات من أجل تحسين التكاليف ضمن القيود التي تديرها.
في المثال الأول، يتطابق عدد المركبات مع عدد الشحنات، وتتشارك جميع المركبات في خصائص التكلفة والموقع الجغرافي نفسها. لكل مركبة تكلفة لكل ساعة تشغيل وتكلفة لكل كيلومتر يتم قطعه، ما يساعد في تقليل وقت السفر والمسافة المقطوعة. قد يتوقّع المرء أن يتم تعيين شحنات لمركبات متعدّدة، ولكن يعرض مثال الاستجابة الحل الأقل تكلفة بالنظر إلى مَعلمات نموذج التكلفة المحدّدة.
اطّلِع على مثال لطلب يتضمّن مركبات متعددة
{ "model": { "globalStartTime": "2023-01-13T16:00:00-08:00", "globalEndTime": "2023-01-14T16:00:00-08:00", "shipments": [ { "deliveries": [ { "arrivalLocation": { "latitude": 37.789456, "longitude": -122.390192 }, "duration": "250s" } ], "pickups": [ { "arrivalLocation": { "latitude": 37.794465, "longitude": -122.394839 }, "duration": "150s" } ], "penaltyCost": 100.0 }, { "deliveries": [ { "arrivalLocation": { "latitude": 37.789116, "longitude": -122.395080 }, "duration": "250s" } ], "pickups": [ { "arrivalLocation": { "latitude": 37.794465, "longitude": -122.394839 }, "duration": "150s" } ], "penaltyCost": 5.0 }, { "deliveries": [ { "arrivalLocation": { "latitude": 37.795242, "longitude": -122.399347 }, "duration": "250s" } ], "pickups": [ { "arrivalLocation": { "latitude": 37.794465, "longitude": -122.394839 }, "duration": "150s" } ], "penaltyCost": 50.0 } ], "vehicles": [ { "endLocation": { "latitude": 37.794465, "longitude": -122.394839 }, "startLocation": { "latitude": 37.794465, "longitude": -122.394839 }, "costPerHour": 50.0, "costPerKilometer": 10.0 }, { "endLocation": { "latitude": 37.794465, "longitude": -122.394839 }, "startLocation": { "latitude": 37.794465, "longitude": -122.394839 }, "costPerHour": 50.0, "costPerKilometer": 10.0 }, { "endLocation": { "latitude": 37.794465, "longitude": -122.394839 }, "startLocation": { "latitude": 37.794465, "longitude": -122.394839 }, "costPerHour": 50.0, "costPerKilometer": 10.0 } ] } }
الاطّلاع على ردّ على الطلب يتضمّن مركبات متعدّدة
{ "routes": [ { "vehicleStartTime": "2023-01-14T00:00:00Z", "vehicleEndTime": "2023-01-14T00:28:22Z", "visits": [ { "isPickup": true, "startTime": "2023-01-14T00:00:00Z", "detour": "0s" }, { "shipmentIndex": 2, "isPickup": true, "startTime": "2023-01-14T00:02:30Z", "detour": "150s" }, { "startTime": "2023-01-14T00:08:55Z", "detour": "150s" }, { "shipmentIndex": 2, "startTime": "2023-01-14T00:21:21Z", "detour": "572s" } ], "transitions": [ { "travelDuration": "0s", "waitDuration": "0s", "totalDuration": "0s", "startTime": "2023-01-14T00:00:00Z" }, { "travelDuration": "0s", "waitDuration": "0s", "totalDuration": "0s", "startTime": "2023-01-14T00:02:30Z" }, { "travelDuration": "235s", "travelDistanceMeters": 795, "waitDuration": "0s", "totalDuration": "235s", "startTime": "2023-01-14T00:05:00Z" }, { "travelDuration": "496s", "travelDistanceMeters": 1893, "waitDuration": "0s", "totalDuration": "496s", "startTime": "2023-01-14T00:13:05Z" }, { "travelDuration": "171s", "travelDistanceMeters": 665, "waitDuration": "0s", "totalDuration": "171s", "startTime": "2023-01-14T00:25:31Z" } ], "metrics": { "performedShipmentCount": 2, "travelDuration": "902s", "waitDuration": "0s", "delayDuration": "0s", "breakDuration": "0s", "visitDuration": "800s", "totalDuration": "1702s", "travelDistanceMeters": 3353 }, "routeCosts": { "model.vehicles.cost_per_kilometer": 33.53, "model.vehicles.cost_per_hour": 23.638888888888889 }, "routeTotalCost": 57.168888888888887 }, { "vehicleIndex": 1 }, { "vehicleIndex": 2 } ], "skippedShipments": [ { "index": 1 } ], "metrics": { "aggregatedRouteMetrics": { "performedShipmentCount": 2, "travelDuration": "902s", "waitDuration": "0s", "delayDuration": "0s", "breakDuration": "0s", "visitDuration": "800s", "totalDuration": "1702s", "travelDistanceMeters": 3353 }, "usedVehicleCount": 1, "earliestVehicleStartTime": "2023-01-14T00:00:00Z", "latestVehicleEndTime": "2023-01-14T00:28:22Z", "totalCost": 62.168888888888887, "costs": { "model.vehicles.cost_per_hour": 23.638888888888889, "model.shipments.penalty_cost": 5, "model.vehicles.cost_per_kilometer": 33.53 } } }
يُعيّن الحلّ جميع الشحنات إلى مركبة واحدة فقط، ويتجاهل شحنة واحدة على الرغم من توفّر عدد كافٍ من المركبات. ويرجع ذلك إلى أنّ تكلفة تشغيل مركبات إضافية مرتفعة جدًا ولا يمكن تبريرها، كما أنّ إكمال الشحنة التي تم تخطّيها ليس فعّالاً من حيث التكلفة لأي مركبة نظرًا إلى انخفاض تكلفة الغرامة.
على الرغم من توفّر سعة المركبة، يمكن لمركبة واحدة تنفيذ جميع الشحنات المخصّصة بأكثر الطرق فعالية من حيث التكلفة. لم يتم ضبط السمة usedIfRouteIsEmpty
للمركبات في الطلب (راجِع مستندات الرسالة Vehicle
(REST وgRPC) للحصول على التفاصيل)، لذا لن يتم تحصيل أي تكلفة إذا لم يتم استخدامها.
يؤدي تغيير مَعلمات التكلفة لتحديد أولويات الحلول الأقصر على مستوى العالم بدلاً من مسارات المركبات الأقصر بشكل فردي إلى مشاركة المزيد من المركبات في الحلّ. يستبدل طلب المثال التالي Vehicle.costPerHour
بـ ShipmentModel.globalDurationCostPerHour
العام، مع إعطاء الأولوية للحلول الأقصر إجمالاً من حيث وقت التشغيل لأي مركبة معيّنة. تمت أيضًا زيادة تكلفة العقوبة الخاصة بـ shipment[1]
للحد من احتمال تخطّيها.
يمكنك الاطّلاع على مثال لطلب باستخدام
globalDurationCostPerHour
{ "model": { "globalStartTime": "2023-01-13T16:00:00-08:00", "globalEndTime": "2023-01-14T16:00:00-08:00", "globalDurationCostPerHour": 150.0, "shipments": [ { "deliveries": [ { "arrivalLocation": { "latitude": 37.789456, "longitude": -122.390192 }, "duration": "250s" } ], "pickups": [ { "arrivalLocation": { "latitude": 37.794465, "longitude": -122.394839 }, "duration": "150s" } ], "penaltyCost": 100.0 }, { "deliveries": [ { "arrivalLocation": { "latitude": 37.789116, "longitude": -122.395080 }, "duration": "250s" } ], "pickups": [ { "arrivalLocation": { "latitude": 37.794465, "longitude": -122.394839 }, "duration": "150s" } ], "penaltyCost": 75.0 }, { "deliveries": [ { "arrivalLocation": { "latitude": 37.795242, "longitude": -122.399347 }, "duration": "250s" } ], "pickups": [ { "arrivalLocation": { "latitude": 37.794465, "longitude": -122.394839 }, "duration": "150s" } ], "penaltyCost": 50.0 } ], "vehicles": [ { "endLocation": { "latitude": 37.794465, "longitude": -122.394839 }, "startLocation": { "latitude": 37.794465, "longitude": -122.394839 }, "costPerKilometer": 10.0 }, { "endLocation": { "latitude": 37.794465, "longitude": -122.394839 }, "startLocation": { "latitude": 37.794465, "longitude": -122.394839 }, "costPerKilometer": 10.0 }, { "endLocation": { "latitude": 37.794465, "longitude": -122.394839 }, "startLocation": { "latitude": 37.794465, "longitude": -122.394839 }, "costPerKilometer": 10.0 } ] } }
توضّح النتيجة أنّ استخدام مَعلمة التكلفة العالمية لكل ساعة يؤدي إلى استخدام جميع المركبات الثلاث بدلاً من مركبة واحدة فقط.
الاطّلاع على ردّ على الطلب باستخدام
globalDurationCostPerHour
{ "routes": [ { "vehicleStartTime": "2023-01-14T00:00:00Z", "vehicleEndTime": "2023-01-14T00:16:20Z", "visits": [ { "shipmentIndex": 2, "isPickup": true, "startTime": "2023-01-14T00:00:00Z", "detour": "0s" }, { "shipmentIndex": 2, "startTime": "2023-01-14T00:09:19Z", "detour": "0s" } ], "transitions": [ { "travelDuration": "0s", "waitDuration": "0s", "totalDuration": "0s", "startTime": "2023-01-14T00:00:00Z" }, { "travelDuration": "409s", "travelDistanceMeters": 1371, "waitDuration": "0s", "totalDuration": "409s", "startTime": "2023-01-14T00:02:30Z" }, { "travelDuration": "171s", "travelDistanceMeters": 665, "waitDuration": "0s", "totalDuration": "171s", "startTime": "2023-01-14T00:13:29Z" } ], "metrics": { "performedShipmentCount": 1, "travelDuration": "580s", "waitDuration": "0s", "delayDuration": "0s", "breakDuration": "0s", "visitDuration": "400s", "totalDuration": "980s", "travelDistanceMeters": 2036 }, "routeCosts": { "model.vehicles.cost_per_kilometer": 20.36 }, "routeTotalCost": 20.36 }, { "vehicleIndex": 1, "vehicleStartTime": "2023-01-14T00:00:00Z", "vehicleEndTime": "2023-01-14T00:18:54Z", "visits": [ { "shipmentIndex": 1, "isPickup": true, "startTime": "2023-01-14T00:00:00Z", "detour": "0s" }, { "shipmentIndex": 1, "startTime": "2023-01-14T00:08:24Z", "detour": "0s" } ], "transitions": [ { "travelDuration": "0s", "waitDuration": "0s", "totalDuration": "0s", "startTime": "2023-01-14T00:00:00Z" }, { "travelDuration": "354s", "travelDistanceMeters": 1192, "waitDuration": "0s", "totalDuration": "354s", "startTime": "2023-01-14T00:02:30Z" }, { "travelDuration": "380s", "travelDistanceMeters": 1190, "waitDuration": "0s", "totalDuration": "380s", "startTime": "2023-01-14T00:12:34Z" } ], "metrics": { "performedShipmentCount": 1, "travelDuration": "734s", "waitDuration": "0s", "delayDuration": "0s", "breakDuration": "0s", "visitDuration": "400s", "totalDuration": "1134s", "travelDistanceMeters": 2382 }, "routeCosts": { "model.vehicles.cost_per_kilometer": 23.82 }, "routeTotalCost": 23.82 }, { "vehicleIndex": 2, "vehicleStartTime": "2023-01-14T00:00:00Z", "vehicleEndTime": "2023-01-14T00:16:14Z", "visits": [ { "isPickup": true, "startTime": "2023-01-14T00:00:00Z", "detour": "0s" }, { "startTime": "2023-01-14T00:06:25Z", "detour": "0s" } ], "transitions": [ { "travelDuration": "0s", "waitDuration": "0s", "totalDuration": "0s", "startTime": "2023-01-14T00:00:00Z" }, { "travelDuration": "235s", "travelDistanceMeters": 795, "waitDuration": "0s", "totalDuration": "235s", "startTime": "2023-01-14T00:02:30Z" }, { "travelDuration": "339s", "travelDistanceMeters": 1276, "waitDuration": "0s", "totalDuration": "339s", "startTime": "2023-01-14T00:10:35Z" } ], "metrics": { "performedShipmentCount": 1, "travelDuration": "574s", "waitDuration": "0s", "delayDuration": "0s", "breakDuration": "0s", "visitDuration": "400s", "totalDuration": "974s", "travelDistanceMeters": 2071 }, "routeCosts": { "model.vehicles.cost_per_kilometer": 20.71 }, "routeTotalCost": 20.71 } ], "metrics": { "aggregatedRouteMetrics": { "performedShipmentCount": 3, "travelDuration": "1888s", "waitDuration": "0s", "delayDuration": "0s", "breakDuration": "0s", "visitDuration": "1200s", "totalDuration": "3088s", "travelDistanceMeters": 6489 }, "usedVehicleCount": 3, "earliestVehicleStartTime": "2023-01-14T00:00:00Z", "latestVehicleEndTime": "2023-01-14T00:18:54Z", "totalCost": 112.14, "costs": { "model.vehicles.cost_per_kilometer": 64.89, "model.global_duration_cost_per_hour": 47.25 } } }
في هذا الردّ، تكون جميع المركبات الثلاث قيد الاستخدام (وفقًا metrics.usedVehicleCount
)، ويتم تخصيص شحنة واحدة لكل مركبة لإكمالها. بما أنّ جميع المركبات الثلاث تتشارك مواقع البداية والنهاية نفسها، بالإضافة إلى costPerKilometer
، يمكن استبدالها ببعضها البعض، وبالتالي لا يهمّ أي شحنة يتم تخصيصها لأي مركبة.
يؤدي globalDurationCostPerHour
إلى أن يعثر المحسّن على حلّ أقصر بشكل عام: الفرق بين earliestVehicleStartTime
وlatestVehicleEndTime
هو 18 دقيقة و54 ثانية فقط، مقارنةً بـ 28 دقيقة و22 ثانية في الرد السابق. ومع ذلك، زاد
معدّل metrics.costs.model.vehicles.cost_per_kilometer
، ما يشير إلى أنّ المركبات الثلاث المستخدَمة قطعت مسافة إجمالية أكبر. يوضّح هذا المثال إحدى الطرق التي يتيح لك من خلالها نموذج التكلفة إجراء مقايضات:
- زيادة تكلفة الوقت الإجمالية: زيادة استخدام المركبات لتقليل وقت الإكمال الإجمالي، مع زيادة مسافة المركبات والوقت المستغرق في النقل.
- زيادة تكلفة وقت المركبة: تقليل استخدام المركبة والوقت المستغرَق في النقل، على حساب إطالة مدة الحلّ الإجمالية
يُرجى العِلم أنّ قيمة globalDurationCostPerHour
البالغة 150.0 في هذا المثال تم ضبطها على ثلاثة أضعاف قيمة costPerHour
البالغة 50.0 للمركبات الفردية من المثال السابق. تتوقّع قيمة التكلفة الإجمالية هذه بشكل فعّال أنّ تعمل المركبات الثلاث معًا في الوقت نفسه، ولكن في الإعدادات العملية، قد لا تعكس هذه الافتراضات الواقع وقد يكون لها في الواقع تأثير سلبي على جودة النتائج.
كما هو موضّح في مَعلمات نموذج التكلفة، يتم التعبير عن جميع مَعلمات التكلفة بوحدات غير بعدية نفسها، ولكن يمكن أن يكون لها معانٍ مختلفة جدًا. عادةً، يجب أن تستند قيم مَعلمات نموذج التكلفة إلى الواقع قدر الإمكان، لأنّ التكاليف الاصطناعية، مثل تلك الواردة في هذا المثال، قد تؤدي إلى تحسين واجهة برمجة التطبيقات لتحقيق أهداف لا تتطابق مع نيتك.