OptimizeToursRequest
menerapkan batasan di seluruh hal berikut:
- Pengiriman, yang memengaruhi cara pengiriman dilakukan
- Kendaraan, yang memengaruhi cara penghitungan rute kendaraan
- Secara global, memengaruhi kendaraan dan pengiriman.
Panduan ini berfokus pada batasan pengiriman penting: rentang waktu.
Periode waktu adalah jenis batasan yang Anda berikan dalam pesan
OptimizeToursRequest
(REST, gRPC) untuk menentukan
batas berbasis waktu untuk aktivitas pengiriman. Jenis batasan ini memengaruhi
kapan dan bagaimana pengiriman dapat dilakukan serta penugasan kendaraan
untuk pengiriman. Dengan batasan ini, pengoptimal memberikan preferensi pada
kendaraan yang paling dapat memenuhi batasan waktu pengiriman.
Batasan pengiriman: jendela waktu
Anda menentukan kapan pengambilan atau pengiriman dapat dilakukan dalam pesan Shipment.VisitRequest
sebagai berikut:
- Gunakan properti
timeWindows
dalam pesan (REST, gRPC) - Tentukan waktu mulai dan berakhir dalam pesan
TimeWindow
(REST, gRPC).
Contoh permintaan dengan batasan jangka waktu
Contoh di sini menggambarkan tiga pengiriman yang berbeda, masing-masing dengan jangka waktu pengiriman sendiri. Agar lebih sederhana, contoh ini menetapkan periode waktu hanya pada deliveries
, tetapi periode waktu juga dapat diterapkan pada pengambilan. Beberapa periode waktu dapat
ditentukan, meskipun contoh ini hanya menggunakan satu per pengiriman VisitRequest
.
Lihat contoh permintaan dengan rentang waktu
{ "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 } ] } }
Contoh respons dengan batasan jangka waktu
Dalam contoh respons, waktu mulai dan berakhir kendaraan adalah 17:35:50 dan
18:17:24. Waktu ini mencerminkan pengoptimalan yang meminimalkan waktu yang diperlukan untuk mengoperasikan kendaraan yang ditentukan dalam permintaan sebagai costPerHour
sekaligus memenuhi semua batasan periode waktu. Menggunakan 17.35.50 sebagai waktu mulai
menghilangkan kebutuhan kendaraan untuk menunggu di lokasi kunjungan hingga
periode waktu kunjungan dimulai. Ini muncul dalam respons sebagai nilai waitDuration
nol.
Lihat respons terhadap contoh permintaan dengan rentang waktu
{ "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 } } }
Jangka waktu telah mengurutkan visits
kendaraan sehingga pengiriman dengan jangka waktu paling awal dikirimkan terlebih dahulu.
shipments[2]
dikirim pada pukul 17.50shipments[1]
dikirimkan pada pukul 18.00shipments[0]
dikirimkan pada pukul 18.07
Contoh permintaan menentukan batasan jendela waktu keras, yang mengharuskan pengiriman diselesaikan dalam jendela tersebut. Jika penyelesaian
VisitRequests
pengiriman dalam jangka waktunya tidak memungkinkan atau
hemat biaya, pengoptimal akan melewati pengiriman. Jika pengiriman memiliki
penaltyCost
, pengoptimal akan menambahkannya ke biaya yang dilaporkan dalam respons
metrics
. Jika tidak, properti skippedMandatoryShipmentCount
dari pesan
OptimizeToursResponse
(REST, gRPC) akan bertambah.
Jika Anda mengubah jangka waktu dengan menggeser jangka waktu shipment[1]
beberapa jam
kemudian (ke 21.00 dari 18.00), hasilnya akan berbeda seperti yang diilustrasikan dalam
contoh berikut.
Lihat contoh permintaan dengan jendela waktu yang tidak dapat dipenuhi
{ "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 } ] } }
Lihat respons terhadap permintaan contoh kedua dengan periode waktu, saat pengiriman dilewati
{ "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 } } }
Dalam contoh ini, rentang waktu yang lebih lambat menyebabkan shipment[1]
dilewati,
karena waktu pengoperasian kendaraan tambahan yang diperlukan untuk menyelesaikan pengiriman
dalam rentang waktu yang ditentukan melebihi biaya penalti pengiriman.
Biaya penalti untuk shipment[1]
muncul di metrics.costs
, dan indeksnya
muncul di skippedShipments
.
Batasan interval waktu yang dapat dilewati
Seperti yang disebutkan secara singkat di Parameter Model Biaya, periode waktu dapat diterapkan sebagai batasan ringan. Batasan ringan berbeda dari batasan berat sebagai berikut:
- Batasan berat: Tidak boleh dilanggar, dan pengoptimal tidak menawarkan solusi yang melanggar batasan, meskipun hal itu berarti melewati pengiriman.
- Batasan ringan: Dapat dilanggar, yang berarti pengoptimal dapat memberikan solusi yang melanggar batasan ringan. Namun, pengoptimal juga menerapkan biaya untuk setiap pelanggaran. Anda memberikan biaya ini sebagai properti tambahan dalam jangka waktu, biasanya sebagai biaya per jam untuk setiap jam sebelum atau setelah jangka waktu terjadinya aktivitas.
Jangka waktu diperlunak dengan menggunakan softStartTime
atau softEndTime
, bukan
startTime
atau endTime
, dan dengan menetapkan
costPerHourBeforeSoftStartTime
atau costPerHourAfterSoftEndTime
.
Gunakan batasan periode waktu fleksibel saat pengambilan atau pengiriman harus terjadi dalam periode waktu tertentu, tetapi pengambilan atau pengiriman dalam periode tersebut tidak mutlak diperlukan. Anda dapat menggunakan batasan jangka waktu tetap dan fleksibel bersama-sama untuk menyatakan tujuan bisnis. Contoh:
- Jendela waktu tetap: Menunjukkan jam buka bisnis pelanggan, seperti dari pukul 09.00 hingga 17.00.
- Rentang waktu fleksibel: Menunjukkan jangka waktu pengiriman atau pengambilan yang cocok dengan notifikasi yang dikirimkan kepada pelanggan, seperti pukul 09.00 hingga 13.00.
Dalam contoh ini, pengiriman yang sebelumnya dilewati karena jangka waktu mulainya terlalu terlambat memiliki batasan waktu mulai yang dilonggarkan. Pengiriman lainnya juga telah melonggarkan waktu berakhirnya rentang waktu.
Lihat contoh permintaan dengan jendela waktu keras dan fleksibel
{ "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 } ] } }
Melihat respons terhadap contoh permintaan dengan jendela waktu keras dan lunak
{ "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 } } }
Jika contoh dengan batasan periode waktu yang ketat dilewati sepenuhnya
shipment[1]
, melonggarkan periode waktu pengirimannya akan menyebabkan pengiriman
sebelum waktu mulai periode waktunya. Demikian pula, dengan memperpanjang waktu akhir pengiriman
lainnya, shipment[2]
dapat dikirimkan setelah periode waktunya
berakhir.
Pada saat yang sama, biaya dan total pengiriman telah berubah:
totalCost
: diturunkan dari 81.283 menjadi 64.797- total pengiriman yang selesai: meningkat dari 2 menjadi 3
Pengoptimal telah menemukan solusi yang lebih murah karena batasan jangka waktu dilonggarkan dibandingkan dengan contoh sebelumnya.
Terakhir, properti metrics.costs
juga menyertakan kunci baru untuk menunjukkan
biaya aktual yang dikeluarkan berdasarkan produk batasan dan durasi
waktu keterlambatan pengiriman. Definisinya yaitu:
costPerHourBeforeSoftStartTime
dari 2.0 dan- waktu antara pengiriman sebenarnya dan awal periode waktu: 2,83583 jam
Hasil:
model.shipments.deliveries.time_windows.cost_per_hour_before_soft_start_time
:
5.6716666666666669.
Dengan metrik ini, Anda dapat melakukan analisis biaya untuk melihat kompromi antara batasan berat dan batasan ringan, yang dapat Anda gunakan untuk menyesuaikan batasan agar lebih sesuai dengan aturan bisnis tertentu. Dalam hal ini, total biaya
kurang dari shipment[1].penalty_cost
20,0. Pengoptimal telah mengidentifikasi bahwa lebih hemat biaya untuk mengirimkan kiriman lebih awal daripada melewatkan pengiriman.