OptimizeToursRequest
áp dụng các ràng buộc đối với những nội dung sau:
- Chuyến vận chuyển, ảnh hưởng đến cách thực hiện chuyến vận chuyển
- Xe, ảnh hưởng đến cách tính toán tuyến đường cho xe
- Trên toàn cầu, ảnh hưởng đến cả xe và lô hàng.
Hướng dẫn này tập trung vào một quy tắc hạn chế quan trọng về việc vận chuyển: khoảng thời gian.
Khoảng thời gian là một loại ràng buộc mà bạn cung cấp trong thông báo OptimizeToursRequest
(REST, gRPC) để chỉ định giới hạn dựa trên thời gian cho các hoạt động vận chuyển. Loại ràng buộc này ảnh hưởng đến cả thời điểm và cách thức thực hiện chuyến hàng, cũng như việc chỉ định xe cho chuyến hàng. Với những ràng buộc này, trình tối ưu hoá sẽ ưu tiên những phương tiện có thể đáp ứng tốt nhất các ràng buộc về thời gian của lô hàng.
Các ràng buộc về lô hàng: khoảng thời gian
Bạn chỉ định thời điểm có thể đến lấy hoặc giao hàng trong thông báo Shipment.VisitRequest
như sau:
- Sử dụng thuộc tính
timeWindows
trong thông báo (REST, gRPC) - Chỉ định thời gian bắt đầu và kết thúc trong thông báo
TimeWindow
(REST, gRPC).
Ví dụ về yêu cầu có các ràng buộc về khung thời gian
Ví dụ ở đây minh hoạ 3 lô hàng riêng biệt, mỗi lô hàng có một khoảng thời gian giao hàng riêng. Để đơn giản, ví dụ này chỉ đặt khung thời gian trên deliveries
, nhưng bạn cũng có thể áp dụng khung thời gian cho việc đến lấy. Bạn có thể chỉ định nhiều khung thời gian, mặc dù ví dụ này chỉ sử dụng một khung thời gian cho mỗi lần giao hàng VisitRequest
.
Xem ví dụ về yêu cầu có khoảng thời gian
{ "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 } ] } }
Ví dụ về phản hồi có các ràng buộc về khung thời gian
Trong phản hồi mẫu, thời gian bắt đầu và kết thúc của xe lần lượt là 17:35:50 và 18:17:24. Những thời gian này phản ánh việc trình tối ưu hoá giảm thiểu thời gian cần thiết để vận hành xe được chỉ định trong yêu cầu dưới dạng costPerHour
trong khi đáp ứng tất cả các điều kiện ràng buộc về khung thời gian. Việc sử dụng 17:35:50 làm thời gian bắt đầu giúp loại bỏ nhu cầu xe phải chờ tại vị trí ghé thăm cho đến khi khung thời gian ghé thăm bắt đầu. Giá trị này xuất hiện trong phản hồi dưới dạng giá trị 0 waitDuration
.
Xem phản hồi cho yêu cầu ví dụ có các khoảng thời gian
{ "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 } } }
Các khung thời gian đã sắp xếp visits
của xe để các lô hàng có khung thời gian sớm nhất được giao trước.
shipments[2]
được giao lúc 17:50shipments[1]
được giao lúc 18:00shipments[0]
được giao lúc 18:07
Yêu cầu mẫu chỉ định các ràng buộc về khung thời gian cố định, yêu cầu hoàn tất việc giao hàng trong các khung thời gian đó. Nếu không thể hoàn tất VisitRequests
của một lô hàng trong bất kỳ khung thời gian nào hoặc không hiệu quả về chi phí, thì trình tối ưu hoá sẽ bỏ qua lô hàng đó. Nếu lô hàng có penaltyCost
, thì trình tối ưu hoá sẽ thêm lô hàng đó vào chi phí được báo cáo trong phản hồi metrics
. Nếu không, thuộc tính skippedMandatoryShipmentCount
của thông báo OptimizeToursResponse
(REST, gRPC) sẽ tăng lên.
Nếu bạn thay đổi khung thời gian bằng cách chuyển khung thời gian của shipment[1]
muộn hơn vài giờ (từ 18:00 thành 21:00), kết quả sẽ khác như minh hoạ trong các ví dụ sau.
Xem ví dụ về yêu cầu có các khung thời gian không thể đáp ứng
{ "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 } ] } }
Xem phản hồi cho yêu cầu ví dụ thứ hai có khung thời gian, trong đó một lô hàng bị bỏ qua
{ "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 } } }
Trong ví dụ này, khoảng thời gian sau đó đã khiến shipment[1]
bị bỏ qua, vì thời gian hoạt động bổ sung của xe cần thiết để hoàn tất việc giao hàng trong khoảng thời gian quy định đã vượt quá chi phí phạt của lô hàng.
Chi phí phạt cho shipment[1]
xuất hiện trong metrics.costs
và chỉ mục của chi phí đó xuất hiện trong skippedShipments
.
Các quy tắc ràng buộc về khoảng thời gian linh hoạt
Như đã đề cập ngắn gọn trong phần Tham số mô hình chi phí, bạn có thể áp dụng các khoảng thời gian dưới dạng các ràng buộc mềm. Các điều kiện ràng buộc linh hoạt khác với các điều kiện ràng buộc cứng như sau:
- Quy tắc ràng buộc chặt chẽ: Không được vi phạm và trình tối ưu hoá không đưa ra giải pháp vi phạm quy tắc ràng buộc, ngay cả khi điều đó có nghĩa là bỏ qua một lô hàng.
- Ràng buộc không bắt buộc: Có thể bị vi phạm, tức là trình tối ưu hoá có thể đưa ra một giải pháp vi phạm ràng buộc không bắt buộc. Tuy nhiên, trình tối ưu hoá cũng áp dụng một chi phí cho mọi lỗi vi phạm. Bạn cung cấp chi phí này dưới dạng một thuộc tính bổ sung trong khung thời gian, thường là chi phí mỗi giờ cho mỗi giờ trước hoặc sau khung thời gian diễn ra hoạt động.
Các khung thời gian được làm mềm bằng cách sử dụng softStartTime
hoặc softEndTime
thay vì startTime
hoặc endTime
tương ứng, và bằng cách đặt costPerHourBeforeSoftStartTime
hoặc costPerHourAfterSoftEndTime
.
Sử dụng các ràng buộc về khung thời gian linh hoạt khi bạn nên đến lấy hoặc giao hàng trong một khung thời gian cụ thể, nhưng không bắt buộc phải đến lấy hoặc giao hàng trong khung thời gian đó. Bạn có thể sử dụng đồng thời các ràng buộc về khung thời gian cứng và mềm để thể hiện mục tiêu kinh doanh. Ví dụ:
- Khung giờ cố định: Cho biết giờ hoạt động của khách hàng, chẳng hạn như từ 9 giờ sáng đến 5 giờ chiều.
- Khung giờ ước chừng: Cho biết khung thời gian giao hàng hoặc đến lấy hàng trùng khớp với thông báo gửi cho khách hàng, chẳng hạn như từ 9 giờ sáng đến 1 giờ chiều.
Trong ví dụ này, lô hàng trước đó bị bỏ qua vì khung thời gian bắt đầu quá muộn đã được nới lỏng ràng buộc về thời gian bắt đầu. Thời gian kết thúc của các lô hàng khác cũng được nới lỏng.
Xem ví dụ về yêu cầu có khung thời gian cố định và linh hoạt
{ "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 } ] } }
Xem phản hồi cho yêu cầu mẫu có khung thời gian cố định và linh hoạt
{ "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 } } }
Trong đó, ví dụ chỉ có các ràng buộc về khung thời gian cố định hoàn toàn bỏ qua shipment[1]
, việc nới lỏng khung thời gian phân phối sẽ khiến nó được phân phối trước thời gian bắt đầu khung thời gian. Tương tự, việc nới lỏng thời gian kết thúc của các lô hàng khác cho phép shipment[2]
được giao sau khi hết khung thời gian.
Đồng thời, cả chi phí và tổng số lô hàng đều đã thay đổi:
totalCost
: giảm từ 81.283 xuống 64.797- tổng số lô hàng đã hoàn tất: tăng từ 2 lên 3
Trình tối ưu hoá đã tìm thấy một giải pháp ít tốn kém hơn vì các ràng buộc về khung thời gian đã được nới lỏng so với ví dụ trước.
Cuối cùng, thuộc tính metrics.costs
cũng bao gồm một khoá mới để cho biết chi phí thực tế phát sinh dựa trên sản phẩm của ràng buộc và khoảng thời gian bị lỡ khung thời gian giao hàng. Đó là:
costPerHourBeforeSoftStartTime
trên 2.0 và- thời gian giữa thời gian giao hàng thực tế và thời điểm bắt đầu của khung thời gian: 2,83583 giờ
Kết quả:
model.shipments.deliveries.time_windows.cost_per_hour_before_soft_start_time
:
5.6716666666666669.
Các chỉ số này cho phép bạn phân tích chi phí để xem sự đánh đổi giữa các ràng buộc cứng và ràng buộc mềm. Bạn có thể sử dụng các chỉ số này để điều chỉnh các ràng buộc cho phù hợp hơn với các quy tắc kinh doanh cụ thể của mình. Trong trường hợp này, tổng chi phí thấp hơn shipment[1].penalty_cost
của 20.0. Công cụ tối ưu hoá đã xác định rằng việc giao hàng sớm sẽ tiết kiệm chi phí hơn so với việc bỏ qua việc giao hàng.