يتم تطبيق قيود من قِبل "OptimizeToursRequest
" على ما يلي:
- الشحنات التي تؤثّر في طريقة تنفيذ الشحنات
- المركبات التي تؤثّر في طريقة احتساب مسارات المركبات
- على مستوى العالم، ما يؤثّر في المركبات والشحنات على حدّ سواء
يركّز هذا الدليل على أحد القيود الأساسية للشحن: المواعيد الزمنية.
النوافذ الزمنية هي نوع من القيد الذي تقدمه في
OptimizeToursRequest
(REST، gRPC) لتحديد
القيود القائمة على الوقت لأنشطة الشحن. يؤثر هذا النوع من القيد
متى وكيف يمكن تنفيذ الشحنة، وكذلك تخصيص المركبة
للشحن. مع هذه القيود، يمنح المحسِّن الأولوية
للمركبات التي يمكنها استيفاء القيود الزمنية للشحنة على أفضل وجه.
قيود الشحن: الفترات الزمنية
يمكنك تحديد موعد لاستلام الطلبات أو توصيلها في Shipment.VisitRequest
.
على النحو التالي:
- استخدام السمة
timeWindows
في الرسالة (REST، gRPC) - حدِّد وقت البدء ووقت الانتهاء في رسالة
TimeWindow
(REST، gRPC).
مثال على طلب يتضمّن قيودًا الفترة الزمنية
يوضح المثال هنا ثلاث شحنات مختلفة، لكل شحنة
فترة التسليم. للتبسيط، يحدّد هذا المثال الفترات الزمنية على deliveries
.
فقط، ولكن يمكن أيضًا تطبيق الفترات الزمنية على عمليات الاستلام. يمكن أن تكون الفترات الزمنية المتعددة
على الرغم من أن هذا المثال يستخدم عنصرًا واحدًا فقط لكل VisitRequest
عملية تسليم.
الاطّلاع على مثال لطلب يتضمّن الفترات الزمنية
{ "populatePolylines": false, "populateTransitionPolylines": false, "model": { "globalStartTime": "2023-01-13T16:00:00Z", "globalEndTime": "2023-01-14T16:00:00Z", "shipments": [ { "deliveries": [ { "arrivalLocation": { "latitude": 37.789456, "longitude": -122.390192 }, "duration": "250s", "timeWindows": [ { "startTime": "2023-01-13T18:00:00Z", "endTime": "2023-01-13T19:00:00Z" } ] } ], "pickups": [ { "arrivalLocation": { "latitude": 37.794465, "longitude": -122.394839 }, "duration": "150s" } ], "penaltyCost": 100.0 }, { "deliveries": [ { "arrivalLocation": { "latitude": 37.789116, "longitude": -122.395080 }, "duration": "250s", "timeWindows": [ { "startTime": "2023-01-13T18:00:00Z", "endTime": "2023-01-13T18:30:00Z" } ] } ], "pickups": [ { "arrivalLocation": { "latitude": 37.794465, "longitude": -122.394839 }, "duration": "150s" } ], "penaltyCost": 20.0 }, { "deliveries": [ { "arrivalLocation": { "latitude": 37.795242, "longitude": -122.399347 }, "duration": "250s", "timeWindows": [ { "startTime": "2023-01-13T17:30:00Z", "endTime": "2023-01-13T18:00:00Z" } ] } ], "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": 40.0, "costPerKilometer": 10.0 } ] } }
مثال على استجابة بقيود الفترة الزمنية
في مثال الردّ، وقت بدء تشغيل المركبة وانتهائها هو 17:35:50
و18:17:24 على التوالي. تعكس هذه الأوقات أنّ المحسِّن يعمل على تقليل الوقت
مطلوبة لتشغيل المركبة المحددة في الطلب على أنها costPerHour
أثناء
وتلبية جميع قيود النافذة الزمنية. استخدام الساعة 17:35:50 كوقت البدء
يلغي الحاجة إلى انتظار المركبة في موقع الزيارة حتى
بدء فترة وقت الزيارة. يظهر هذا الحقل في الردّ على شكل صفر waitDuration
.
القيم.
الاطّلاع على ردّ على مثال الطلب مع الفترات الزمنية
{ "routes": [ { "vehicleStartTime": "2023-01-13T17:35:50Z", "vehicleEndTime": "2023-01-13T18:17:24Z", "visits": [ { "isPickup": true, "startTime": "2023-01-13T17:35:50Z", "detour": "0s" }, { "shipmentIndex": 1, "isPickup": true, "startTime": "2023-01-13T17:38:20Z", "detour": "150s" }, { "shipmentIndex": 2, "isPickup": true, "startTime": "2023-01-13T17:40:50Z", "detour": "300s" }, { "shipmentIndex": 2, "startTime": "2023-01-13T17:50:09Z", "detour": "0s" }, { "shipmentIndex": 1, "startTime": "2023-01-13T18:00:00Z", "detour": "796s" }, { "startTime": "2023-01-13T18:07:35Z", "detour": "1520s" } ], "transitions": [ { "travelDuration": "0s", "waitDuration": "0s", "totalDuration": "0s", "startTime": "2023-01-13T17:35:50Z" }, { "travelDuration": "0s", "waitDuration": "0s", "totalDuration": "0s", "startTime": "2023-01-13T17:38:20Z" }, { "travelDuration": "0s", "waitDuration": "0s", "totalDuration": "0s", "startTime": "2023-01-13T17:40:50Z" }, { "travelDuration": "409s", "travelDistanceMeters": 1371, "waitDuration": "0s", "totalDuration": "409s", "startTime": "2023-01-13T17:43:20Z" }, { "travelDuration": "341s", "travelDistanceMeters": 1312, "waitDuration": "0s", "totalDuration": "341s", "startTime": "2023-01-13T17:54:19Z" }, { "travelDuration": "205s", "travelDistanceMeters": 636, "waitDuration": "0s", "totalDuration": "205s", "startTime": "2023-01-13T18:04:10Z" }, { "travelDuration": "339s", "travelDistanceMeters": 1276, "waitDuration": "0s", "totalDuration": "339s", "startTime": "2023-01-13T18:11:45Z" } ], "metrics": { "performedShipmentCount": 3, "travelDuration": "1294s", "waitDuration": "0s", "delayDuration": "0s", "breakDuration": "0s", "visitDuration": "1200s", "totalDuration": "2494s", "travelDistanceMeters": 4595 }, "routeCosts": { "model.vehicles.cost_per_hour": 27.711111111111112, "model.vehicles.cost_per_kilometer": 45.95 }, "routeTotalCost": 73.661111111111111 } ], "metrics": { "aggregatedRouteMetrics": { "performedShipmentCount": 3, "travelDuration": "1294s", "waitDuration": "0s", "delayDuration": "0s", "breakDuration": "0s", "visitDuration": "1200s", "totalDuration": "2494s", "travelDistanceMeters": 4595 }, "usedVehicleCount": 1, "earliestVehicleStartTime": "2023-01-13T17:35:50Z", "latestVehicleEndTime": "2023-01-13T18:17:24Z", "totalCost": 73.661111111111111, "costs": { "model.vehicles.cost_per_hour": 27.711111111111112, "model.vehicles.cost_per_kilometer": 45.95 } } }
طلبت الفترات الزمنية visits
للمركبة حتى تصبح الشحنات ذات
يتم تسليم الفترات الزمنية الأقدم أولاً.
- يتم تسليم
shipments[2]
في الساعة 5:50 بعد الظهر - يتم تسليم
shipments[1]
عند الساعة 6:00 مساءً - يتم تسليم
shipments[0]
في الساعة 6:07 مساءً
يحدّد مثال الطلب قيودًا صارمة على النوافذ الزمنية، ما يتطلّب اكتمال عمليات الإرسال خلال هذه النوافذ. إذا كان إكمال شحنة
إنّ VisitRequests
خلال أي من فتراته الزمنية غير ممكن أو
فعّالة من حيث التكلفة، يتخطى المُحسّن الشحن. إذا كان للشحن
penaltyCost
، يضيفه محسّن الإحالات الناجحة إلى التكاليف المسجّلة كاستجابة للطلب
metrics
وبخلاف ذلك، لا يمكن استخدام الخاصية skippedMandatoryShipmentCount
تزيد رسالة OptimizeToursResponse
(REST وgRPC).
إذا غيّرت الفترات الزمنية من خلال تغيير فترة shipment[1]
بعد عدة ساعات
لاحقًا (إلى 21:00 من 18:00)، ستكون النتائج مختلفة كما هو موضّح في المثالين التاليين.
الاطّلاع على مثال لطلب يتضمّن فترات زمنية غير مسموح بها الشعور بالرضا
{ "populatePolylines": false, "populateTransitionPolylines": false, "model": { "globalStartTime": "2023-01-13T16:00:00Z", "globalEndTime": "2023-01-14T16:00:00Z", "shipments": [ { "deliveries": [ { "arrivalLocation": { "latitude": 37.789456, "longitude": -122.390192 }, "duration": "250s", "timeWindows": [ { "startTime": "2023-01-13T18:00:00Z", "endTime": "2023-01-13T19:00:00Z" } ] } ], "pickups": [ { "arrivalLocation": { "latitude": 37.794465, "longitude": -122.394839 }, "duration": "150s" } ], "penaltyCost": 100.0 }, { "deliveries": [ { "arrivalLocation": { "latitude": 37.789116, "longitude": -122.395080 }, "duration": "250s", "timeWindows": [ { "startTime": "2023-01-13T21:00:00Z", "endTime": "2023-01-13T21:30:00Z" } ] } ], "pickups": [ { "arrivalLocation": { "latitude": 37.794465, "longitude": -122.394839 }, "duration": "150s" } ], "penaltyCost": 20.0 }, { "deliveries": [ { "arrivalLocation": { "latitude": 37.795242, "longitude": -122.399347 }, "duration": "250s", "timeWindows": [ { "startTime": "2023-01-13T17:30:00Z", "endTime": "2023-01-13T18:00:00Z" } ] } ], "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": 40.0, "costPerKilometer": 10.0 } ] } }
الاطّلاع على ردّ على مثال الطلب الثاني مع الفترات الزمنية التي يتم فيها تخطّي شحنة
{ "routes": [ { "vehicleStartTime": "2023-01-13T17:37:49Z", "vehicleEndTime": "2023-01-13T18:09:49Z", "visits": [ { "isPickup": true, "startTime": "2023-01-13T17:37:49Z", "detour": "0s" }, { "shipmentIndex": 2, "isPickup": true, "startTime": "2023-01-13T17:40:19Z", "detour": "150s" }, { "shipmentIndex": 2, "startTime": "2023-01-13T17:49:38Z", "detour": "0s" }, { "startTime": "2023-01-13T18:00:00Z", "detour": "946s" } ], "transitions": [ { "travelDuration": "0s", "waitDuration": "0s", "totalDuration": "0s", "startTime": "2023-01-13T17:37:49Z" }, { "travelDuration": "0s", "waitDuration": "0s", "totalDuration": "0s", "startTime": "2023-01-13T17:40:19Z" }, { "travelDuration": "409s", "travelDistanceMeters": 1371, "waitDuration": "0s", "totalDuration": "409s", "startTime": "2023-01-13T17:42:49Z" }, { "travelDuration": "372s", "travelDistanceMeters": 1348, "waitDuration": "0s", "totalDuration": "372s", "startTime": "2023-01-13T17:53:48Z" }, { "travelDuration": "339s", "travelDistanceMeters": 1276, "waitDuration": "0s", "totalDuration": "339s", "startTime": "2023-01-13T18:04:10Z" } ], "metrics": { "performedShipmentCount": 2, "travelDuration": "1120s", "waitDuration": "0s", "delayDuration": "0s", "breakDuration": "0s", "visitDuration": "800s", "totalDuration": "1920s", "travelDistanceMeters": 3995 }, "routeCosts": { "model.vehicles.cost_per_kilometer": 39.95, "model.vehicles.cost_per_hour": 21.333333333333332 }, "routeTotalCost": 61.283333333333331 } ], "skippedShipments": [ { "index": 1 } ], "metrics": { "aggregatedRouteMetrics": { "performedShipmentCount": 2, "travelDuration": "1120s", "waitDuration": "0s", "delayDuration": "0s", "breakDuration": "0s", "visitDuration": "800s", "totalDuration": "1920s", "travelDistanceMeters": 3995 }, "usedVehicleCount": 1, "earliestVehicleStartTime": "2023-01-13T17:37:49Z", "latestVehicleEndTime": "2023-01-13T18:09:49Z", "totalCost": 81.283333333333331, "costs": { "model.shipments.penalty_cost": 20, "model.vehicles.cost_per_hour": 21.333333333333332, "model.vehicles.cost_per_kilometer": 39.95 } } }
في هذا المثال، تسبّبت الفترة الزمنية اللاحقة في تخطّي shipment[1]
،
لأن وقت تشغيل المركبة الإضافي المطلوب لإنجاز الشحنة
تجاوز التسليم خلال الفترة الزمنية المحدّدة تكلفة العقوبة المفروضة على الشحنة.
تظهر تكلفة العقوبة المفروضة على shipment[1]
في metrics.costs
والفهرس الخاص بها.
يظهر في skippedShipments
.
قيود نافذة زمنية خفيفة
كما ذكرنا بإيجاز في معلمات نماذج التكلفة، يمكن تطبيق الفترات الزمنية كقيود سلسة. تختلف القيود غير الصارمة عن القيود الصارمة على النحو التالي:
- القيود الصارمة: لا يمكن انتهاكها، ولا يقدّم المحسِّن حلًا ينتهك القيد، حتى لو كان ذلك يعني تخطّي shipment.
- القيود غير الصارمة: قد يتم انتهاكها، ما يعني أنّ أداة التحسين قد تقدّم حلًا ينتهك قيدًا غير صارم. ومع ذلك، يطبّق المحسِّن تكلفة أيضًا على أي انتهاك. وتقدم هذه التكلفة كـ موقع إضافي في الفترة الزمنية، عادةً كتكلفة في الساعة كل ساعة قبل أو بعد الفترة الزمنية التي يحدث فيها النشاط.
يتم تخفيف النوافذ الزمنية باستخدام softStartTime
أو softEndTime
بدلاً من
startTime
أو endTime
على التوالي، ومن خلال ضبط
costPerHourBeforeSoftStartTime
أو costPerHourAfterSoftEndTime
.
استخدِم قيود زمنية مبسّطة عندما ينبغي استلام الطلبات أو تسليمها. خلال فترة زمنية محددة، ولكن لا يمكن استلام الطلب أو التسليم خلال هذه الفترة هو مطلوب للغاية. يمكنك استخدام قيود فترات زمنية صعبة وسلسة معًا للتعبير عن أهداف العمل. على سبيل المثال:
- فترة زمنية محددة: تشير إلى ساعات عمل العميل، مثل من 9 صباحًا إلى 5 مساءً.
- الفترة الزمنية المتبقية: تشير هذه السمة إلى الإطار الزمني للتسليم أو الاستلام تتطابق مع الإشعار المُرسَل إلى العميل، مثلاً من 9 صباحًا إلى 1 مساءً.
في هذا المثال، الشحنة التي تم تخطيها مسبقًا لأن وقتها بدأت متأخرة جدًا في التخفيف من قيود وقت البدء. الآخر للشحنات لها فترات زمنية أيضًا تخفيض أوقات الانتهاء.
الاطّلاع على مثال على طلب يتضمّن وقتًا عصيبًا ورسمًا نوافذ
{ "populatePolylines": false, "populateTransitionPolylines": false, "model": { "globalStartTime": "2023-01-13T16:00:00Z", "globalEndTime": "2023-01-14T16:00:00Z", "shipments": [ { "deliveries": [ { "arrivalLocation": { "latitude": 37.789456, "longitude": -122.390192 }, "duration": "250s", "timeWindows": [ { "startTime": "2023-01-13T18:00:00Z", "softEndTime": "2023-01-13T19:00:00Z", "costPerHourAfterSoftEndTime": 2.0 } ] } ], "pickups": [ { "arrivalLocation": { "latitude": 37.794465, "longitude": -122.394839 }, "duration": "150s" } ], "penaltyCost": 100.0 }, { "deliveries": [ { "arrivalLocation": { "latitude": 37.789116, "longitude": -122.395080 }, "duration": "250s", "timeWindows": [ { "softStartTime": "2023-01-13T21:00:00Z", "endTime": "2023-01-13T21:30:00Z", "costPerHourBeforeSoftStartTime": 2.0 } ] } ], "pickups": [ { "arrivalLocation": { "latitude": 37.794465, "longitude": -122.394839 }, "duration": "150s" } ], "penaltyCost": 20.0 }, { "deliveries": [ { "arrivalLocation": { "latitude": 37.795242, "longitude": -122.399347 }, "duration": "250s", "timeWindows": [ { "startTime": "2023-01-13T17:30:00Z", "softEndTime": "2023-01-13T18:00:00Z", "costPerHourAfterSoftEndTime": 2.0 } ] } ], "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": 40.0, "costPerKilometer": 10.0 } ] } }
الاطّلاع على استجابة لنموذج الطلب مع فترات زمنية محددة بدقة وغير محددة بدقة
{ "routes": [ { "vehicleStartTime": "2023-01-13T17:48:35Z", "vehicleEndTime": "2023-01-13T18:24:28Z", "visits": [ { "isPickup": true, "startTime": "2023-01-13T17:48:35Z", "detour": "0s" }, { "shipmentIndex": 1, "isPickup": true, "startTime": "2023-01-13T17:51:05Z", "detour": "150s" }, { "shipmentIndex": 2, "isPickup": true, "startTime": "2023-01-13T17:53:35Z", "detour": "300s" }, { "startTime": "2023-01-13T18:00:00Z", "detour": "300s" }, { "shipmentIndex": 1, "startTime": "2023-01-13T18:07:42Z", "detour": "493s" }, { "shipmentIndex": 2, "startTime": "2023-01-13T18:17:27Z", "detour": "873s" } ], "transitions": [ { "travelDuration": "0s", "waitDuration": "0s", "totalDuration": "0s", "startTime": "2023-01-13T17:48:35Z" }, { "travelDuration": "0s", "waitDuration": "0s", "totalDuration": "0s", "startTime": "2023-01-13T17:51:05Z" }, { "travelDuration": "0s", "waitDuration": "0s", "totalDuration": "0s", "startTime": "2023-01-13T17:53:35Z" }, { "travelDuration": "235s", "travelDistanceMeters": 795, "waitDuration": "0s", "totalDuration": "235s", "startTime": "2023-01-13T17:56:05Z" }, { "travelDuration": "212s", "travelDistanceMeters": 791, "waitDuration": "0s", "totalDuration": "212s", "startTime": "2023-01-13T18:04:10Z" }, { "travelDuration": "335s", "travelDistanceMeters": 1204, "waitDuration": "0s", "totalDuration": "335s", "startTime": "2023-01-13T18:11:52Z" }, { "travelDuration": "171s", "travelDistanceMeters": 665, "waitDuration": "0s", "totalDuration": "171s", "startTime": "2023-01-13T18:21:37Z" } ], "metrics": { "performedShipmentCount": 3, "travelDuration": "953s", "waitDuration": "0s", "delayDuration": "0s", "breakDuration": "0s", "visitDuration": "1200s", "totalDuration": "2153s", "travelDistanceMeters": 3455 }, "routeCosts": { "model.shipments.deliveries.time_windows.cost_per_hour_after_soft_end_time": 0.58166666666666667, "model.shipments.deliveries.time_windows.cost_per_hour_before_soft_start_time": 5.7433333333333332, "model.vehicles.cost_per_hour": 23.922222222222221, "model.vehicles.cost_per_kilometer": 34.55 }, "routeTotalCost": 64.797222222222217 } ], "metrics": { "aggregatedRouteMetrics": { "performedShipmentCount": 3, "travelDuration": "953s", "waitDuration": "0s", "delayDuration": "0s", "breakDuration": "0s", "visitDuration": "1200s", "totalDuration": "2153s", "travelDistanceMeters": 3455 }, "usedVehicleCount": 1, "earliestVehicleStartTime": "2023-01-13T17:48:35Z", "latestVehicleEndTime": "2023-01-13T18:24:28Z", "totalCost": 64.797222222222217, "costs": { "model.vehicles.cost_per_kilometer": 34.55, "model.shipments.deliveries.time_windows.cost_per_hour_before_soft_start_time": 5.7433333333333332, "model.shipments.deliveries.time_windows.cost_per_hour_after_soft_end_time": 0.58166666666666667, "model.vehicles.cost_per_hour": 23.922222222222221 } } }
في المثال الذي يتضمّن قيودًا صارمة على الفترة الزمنية فقط، تم تخطّي المحتوى بالكامل
shipment[1]
، ولكن عند تخفيف الفترة الزمنية لإرساله، يتم إرساله
قبل بدء الفترة الزمنية. وبالمثل، فإن تخفيف أوقات انتهاء
شحنات أخرى سمحت بتسليم "shipment[2]
" بعد الفترة الزمنية المحدّدة
تنتهي.
وفي الوقت نفسه، تغيّرت كلّ من التكاليف وإجمالي الشحنات:
totalCost
: انخفاض من 81.283 إلى 64.797- إجمالي الشحنات المكتملة: زيادة من 2 إلى 3
عثرت أداة تحسين الأداء على حلّ أقل تكلفة لأنّه تمّ تخفيف قيود النافذة الزمنية مقارنةً بالمثال السابق.
أخيرًا، تتضمّن السمة metrics.costs
أيضًا مفتاحًا جديدًا للإشارة إلى
التكلفة الفعلية التي يتم تكبدها بناءً على ناتج القيد وطول
الوقت الذي فاتته فترة التسليم. والمقصود:
costPerHourBeforeSoftStartTime
من 2.0 و- الوقت بين التسليم الفعلي وبداية الفترة الزمنية: 2.83583 ساعة
النتيجة:
model.shipments.deliveries.time_windows.cost_per_hour_before_soft_start_time
:
5.6716666666666669.
تسمح لك هذه المقاييس بإجراء تحليل التكاليف لمعرفة الموازنة بين فرق العمل
القيود والقيود المرنة، والتي يمكنك استخدامها لضبط قيودك
أكثر ملاءمة لقواعد النشاط التجاري المحدّدة الخاصة بك. في هذه الحالة، تبلغ التكلفة الإجمالية
أقل من shipment[1].penalty_cost
من 20.0. حدّد المعلِن
أنّ تسليم الشحنة في وقت مبكر أكثر فعالية من حيث التكلفة
تخطي الشحنة.