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 yang penting: periode 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
waktu dan cara pengiriman dapat dilakukan serta penetapan kendaraan
untuk pengiriman. Dengan batasan ini, pengoptimal memberikan preferensi kepada
kendaraan yang paling dapat memenuhi batasan waktu pengiriman.
Batasan pengiriman: periode waktu
Anda menentukan kapan pengambilan atau pengiriman dapat terjadi dalam pesan Shipment.VisitRequest
sebagai berikut:
- Menggunakan properti
timeWindows
dalam pesan (REST, gRPC) - Tentukan waktu mulai dan berakhir dalam pesan
TimeWindow
(REST, gRPC).
Contoh permintaan dengan batasan periode waktu
Contoh di sini mengilustrasikan tiga pengiriman yang berbeda, masing-masing dengan periode pengirimannya sendiri. Agar lebih mudah, contoh ini menetapkan periode waktu hanya pada deliveries
, tetapi periode waktu juga dapat diterapkan ke pengambilan. Beberapa periode waktu dapat ditentukan, meskipun contoh ini hanya menggunakan satu per VisitRequest
pengiriman.
Lihat contoh permintaan dengan periode 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 periode waktu
Dalam contoh respons, waktu mulai dan berakhir kendaraan masing-masing adalah 17.35.50 dan
18.17.24. Waktu ini mencerminkan pengoptimal 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
akan menghilangkan kebutuhan kendaraan untuk menunggu di lokasi kunjungan hingga
periode waktu kunjungan dimulai. Nilai ini muncul dalam respons sebagai nilai waitDuration
nol.
Lihat respons untuk contoh permintaan dengan periode 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 dikirim terlebih dahulu.
shipments[2]
dikirim pada pukul 17.50shipments[1]
dikirim pada pukul 18.00shipments[0]
dikirim pukul 18.07
Contoh permintaan menentukan batasan periode waktu keras, yang mengharuskan pengiriman diselesaikan dalam periode tersebut. Jika menyelesaikan VisitRequests
pengiriman dalam periode 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 meningkat.
Jika Anda mengubah periode waktu dengan menggeser periode shipment[1]
beberapa jam
kemudian (menjadi 21.00 dari 18.00), hasilnya akan berbeda seperti yang diilustrasikan dalam
contoh berikut.
Lihat contoh permintaan dengan periode 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 untuk contoh permintaan 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, periode waktu yang lebih lambat telah menyebabkan shipment[1]
dilewati,
karena waktu pengoperasian kendaraan tambahan yang diperlukan untuk menyelesaikan pengiriman
dalam periode waktu yang ditentukan melebihi biaya penalti pengiriman.
Biaya penalti untuk shipment[1]
muncul di metrics.costs
, dan indeksnya
muncul di skippedShipments
.
Batasan periode waktu yang fleksibel
Seperti yang disebutkan secara singkat di Parameter Model Biaya, periode waktu dapat diterapkan sebagai batasan lunak. Batasan lunak berbeda dengan batasan keras sebagai berikut:
- Batasan ketat: Tidak dapat dilanggar, dan pengoptimal tidak menawarkan solusi yang melanggar batasan, meskipun hal itu berarti melewati pengiriman.
- Batasan lunak: Dapat dilanggar, yang berarti pengoptimal dapat memberikan solusi yang melanggar batasan lunak. 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.
Periode waktu diperlunak dengan menggunakan softStartTime
atau softEndTime
, bukan
startTime
atau endTime
, dan dengan menetapkan
costPerHourBeforeSoftStartTime
atau costPerHourAfterSoftEndTime
.
Gunakan batasan periode waktu yang fleksibel saat pengambilan atau pengiriman harus terjadi dalam periode waktu yang ditentukan, tetapi pengambilan atau pengiriman dalam periode tersebut tidak diperlukan secara mutlak. Anda dapat menggunakan batasan periode waktu hard dan soft secara bersamaan untuk menyatakan tujuan bisnis. Contoh:
- Periode waktu tetap: Menunjukkan jam buka pelanggan, seperti dari pukul 09.00 hingga 17.00.
- Jendela 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 periode waktunya dimulai terlalu terlambat memiliki batasan waktu mulai yang dilonggarkan. Pengiriman lainnya juga telah memiliki waktu akhir periode waktu yang lebih longgar.
Lihat contoh permintaan dengan periode waktu tegas dan periode waktu lunak
{ "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 periode waktu hard dan soft
{ "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 sepenuhnya melewati
shipment[1]
, melunakkan periode waktu pengirimannya akan menyebabkannya dikirim
sebelum waktu mulai periode waktunya. Demikian pula, dengan memperlunak waktu akhir
pengiriman lainnya, shipment[2]
dapat dikirim setelah periode waktunya
berakhir.
Pada saat yang sama, biaya dan total pengiriman telah berubah:
totalCost
: turun dari 81.283 menjadi 64.797- total pengiriman yang selesai: meningkat dari 2 menjadi 3
Pengoptimal telah menemukan solusi yang lebih murah karena batasan periode 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 saat periode pengiriman terlewat. 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.
Metrik ini memungkinkan Anda melakukan analisis biaya untuk melihat kompromi antara batasan
keras dan batasan lunak, 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
sebesar 20,0. Pengoptimal telah mengidentifikasi
bahwa lebih hemat biaya untuk mengirimkan paket lebih awal daripada
melewatkan pengiriman.