本指南介绍了 loadDemands
和 loadLimits
,以及它们之间的关系。
如提货和送货时间范围限制中所述,OptimizeToursRequest
消息(REST、gRPC)包含许多属性,用于指定针对要优化的问题的限制条件。多个 OptimizeToursRequest
属性表示加载限制。
规划路线时,必须考虑车辆和货物的物理属性。
- 车辆:
loadLimits
属性指定了车辆可以处理的最大负载。请参阅Vehicle
消息的(REST、gRPC)文档。 - 发运:
loadDemands
属性指定给定装运消耗的负载。请参阅Shipment
消息的(REST、gRPC)文档。
结合这两个约束条件,优化器能够以最符合您的车队容量和货运需求的方式将货物适当地分配给车辆。
本文档的其余部分将详细介绍 loadLimits
和 loadDemands
。
加载需求和限制:类型
您可以用类型表示每个负载需求和限制限制条件。
您可以提供自己的一组加载类型,如以下示例所示:
- 权重
- 卷
- 线性测量
- 所运输物品或设备的名称
本指南使用 weightKg
作为示例类型。
Shipment.loadDemands
和 Vehicle.loadLimits
都使用 Protocol Buffers map
类型,其中 string
键表示负载类型。
Shipment.loadDemands
值使用 Load
消息(REST、gRPC)。
Load
消息具有单个 amount
属性,表示完成指定类型的装运所需的容量。
Vehicle.loadLimits
值使用 LoadLimit
消息(REST、gRPC)。LoadLimit
消息具有多个属性,其中 maxLoad
表示车辆在指定类型的最大负载能力。
仅当分配的车辆的 loadLimits
具有匹配的加载类型键时,运单的 loadDemands
才会消耗两者。例如,loadDemands
为以下项的运单:
"loadDemands": {
"weightKg": {
"amount": 50
}
}
需要 50 个 weightKg
类型的加载单元才能完成装运。一辆loadLimits
属于以下车型的车辆:
"loadLimits": {
"weightKg": {
"maxLoad": 100
}
}
可能能够完成装运,因为车辆的 maxLoad
(属于 weightKg
类型)大于或等于运单的 loadDemands
(属于 weightKg
类型)。但是,一辆 loadLimits
属于以下内容的车辆:
"loadLimits": {
"equipmentRackStorage": {
"maxLoad": 10
}
}
由于没有weightKg
负载限制,因此隐式具有不受限制的 weightKg
容量限制,因此车辆不受运单重量需求的限制。
加载货物和车辆之间的移交作业
当货物由车辆取走和送达时,货物的 loadDemand
会在货物和车辆之间转移。您可以在指定车辆的 OptimizeToursResponse
消息的 (REST、gRPC)routes.transitions
条目中查看车辆的加载情况。操作顺序如下:
- 运送所需的负载能力以
loadDemand
的形式指定。 - 车辆由其分配的车辆取走,且车辆的
vehicleLoads
会随运单的loadDemand
金额增加。此转移作业在响应消息中由正visits.loadDemands
表示。 - 车辆负责交付货物,并且车辆的
vehicleLoads
会减少所交付货物的loadDemand
数量。在响应消息中,此传输由否定visits.loadDemands
表示。
车辆的 vehicleLoads
在其路线上的任何时间点都不能超过其指定的 loadLimits
。
包含负载需求和限制的完整示例
查看包含负载需求和限制的示例请求
{ "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" } ], "pickups": [ { "arrivalLocation": { "latitude": 37.794465, "longitude": -122.394839 }, "duration": "150s" } ], "penaltyCost": 100.0, "loadDemands": { "weightKg": { "amount": 50 } } }, { "deliveries": [ { "arrivalLocation": { "latitude": 37.789116, "longitude": -122.395080 }, "duration": "250s" } ], "pickups": [ { "arrivalLocation": { "latitude": 37.794465, "longitude": -122.394839 }, "duration": "150s" } ], "penaltyCost": 15.0, "loadDemands": { "weightKg": { "amount": 10 } } }, { "deliveries": [ { "arrivalLocation": { "latitude": 37.795242, "longitude": -122.399347 }, "duration": "250s" } ], "pickups": [ { "arrivalLocation": { "latitude": 37.794465, "longitude": -122.394839 }, "duration": "150s" } ], "penaltyCost": 50.0, "loadDemands": { "weightKg": { "amount": 80 } } } ], "vehicles": [ { "endLocation": { "latitude": 37.794465, "longitude": -122.394839 }, "startLocation": { "latitude": 37.794465, "longitude": -122.394839 }, "costPerHour": 40.0, "costPerKilometer": 10.0, "loadLimits": { "weightKg": { "maxLoad": 100 } } } ] } }
示例请求包含几个与加载相关的参数:
shipments[0]
的加载需求为 50 个weightKg
。shipments[1]
的加载需求为 10weightKg
。shipments[2]
的加载需求为 80weightKg
。vehicles[0]
的负载上限为 100 个weightKg
。
查看对包含负载需求和限制的请求的响应
{ "routes": [ { "vehicleStartTime": "2023-01-13T16:00:00Z", "vehicleEndTime": "2023-01-13T16:43:27Z", "visits": [ { "isPickup": true, "startTime": "2023-01-13T16:00:00Z", "detour": "0s", "loadDemands": { "weightKg": { "amount": "50" } } }, { "shipmentIndex": 1, "isPickup": true, "startTime": "2023-01-13T16:02:30Z", "detour": "150s", "loadDemands": { "weightKg": { "amount": "10" } } }, { "startTime": "2023-01-13T16:08:55Z", "detour": "150s", "loadDemands": { "weightKg": { "amount": "-50" } } }, { "shipmentIndex": 1, "startTime": "2023-01-13T16:16:37Z", "detour": "343s", "loadDemands": { "weightKg": { "amount": "-10" } } }, { "shipmentIndex": 2, "isPickup": true, "startTime": "2023-01-13T16:27:07Z", "detour": "1627s", "loadDemands": { "weightKg": { "amount": "80" } } }, { "shipmentIndex": 2, "startTime": "2023-01-13T16:36:26Z", "detour": "0s", "loadDemands": { "weightKg": { "amount": "-80" } } } ], "transitions": [ { "travelDuration": "0s", "waitDuration": "0s", "totalDuration": "0s", "startTime": "2023-01-13T16:00:00Z", "vehicleLoads": { "weightKg": {} } }, { "travelDuration": "0s", "waitDuration": "0s", "totalDuration": "0s", "startTime": "2023-01-13T16:02:30Z", "vehicleLoads": { "weightKg": { "amount": "50" } } }, { "travelDuration": "235s", "travelDistanceMeters": 795, "waitDuration": "0s", "totalDuration": "235s", "startTime": "2023-01-13T16:05:00Z", "vehicleLoads": { "weightKg": { "amount": "60" } } }, { "travelDuration": "212s", "travelDistanceMeters": 791, "waitDuration": "0s", "totalDuration": "212s", "startTime": "2023-01-13T16:13:05Z", "vehicleLoads": { "weightKg": { "amount": "10" } } }, { "travelDuration": "380s", "travelDistanceMeters": 1190, "waitDuration": "0s", "totalDuration": "380s", "startTime": "2023-01-13T16:20:47Z", "vehicleLoads": { "weightKg": {} } }, { "travelDuration": "409s", "travelDistanceMeters": 1371, "waitDuration": "0s", "totalDuration": "409s", "startTime": "2023-01-13T16:29:37Z", "vehicleLoads": { "weightKg": { "amount": "80" } } }, { "travelDuration": "171s", "travelDistanceMeters": 665, "waitDuration": "0s", "totalDuration": "171s", "startTime": "2023-01-13T16:40:36Z", "vehicleLoads": { "weightKg": {} } } ], "metrics": { "performedShipmentCount": 3, "travelDuration": "1407s", "waitDuration": "0s", "delayDuration": "0s", "breakDuration": "0s", "visitDuration": "1200s", "totalDuration": "2607s", "travelDistanceMeters": 4812, "maxLoads": { "weightKg": { "amount": "80" } } }, "routeCosts": { "model.vehicles.cost_per_kilometer": 48.12, "model.vehicles.cost_per_hour": 28.966666666666665 }, "routeTotalCost": 77.086666666666659 } ], "metrics": { "aggregatedRouteMetrics": { "performedShipmentCount": 3, "travelDuration": "1407s", "waitDuration": "0s", "delayDuration": "0s", "breakDuration": "0s", "visitDuration": "1200s", "totalDuration": "2607s", "travelDistanceMeters": 4812, "maxLoads": { "weightKg": { "amount": "80" } } }, "usedVehicleCount": 1, "earliestVehicleStartTime": "2023-01-13T16:00:00Z", "latestVehicleEndTime": "2023-01-13T16:43:27Z", "totalCost": 77.086666666666659, "costs": { "model.vehicles.cost_per_hour": 28.966666666666665, "model.vehicles.cost_per_kilometer": 48.12 } } }
添加的加载限制会影响 visits
的顺序:
- 已取走
shipment[0]
- 已取走
shipment[1]
shipment[0]
已送达shipment[1]
已送达- 已取走
shipment[2]
shipment[2]
已送达
此订单反映了车辆无法同时完成三批发货,因为其总loadDemands
超过车辆的 loadLimits
。
每个 visits
条目都包含因完成 Visit
而导致的车辆负载变化。负载为正值表示装运负载,负值表示装运卸载。
在 Transition
期间,每个 transitions
条目都包含车辆总负载。例如,transitions[2]
的 weightKg
负载为 60,表示 shipment[0]
和 shipment[1]
的负载组合。
指标对象 routes[0].metrics
和 metrics.aggregatedRouteMetrics
包含 maxLoads
属性。类型 weightKg
的值为 80,表示将 shipments[2]
运送到送货地点的车辆路线部分。
软负载限制限制条件
与自提和送货时间范围限制中所述的时间范围一样,负载限制限制具有硬性变体和软性变体。LoadLimit
消息的 maxLoad
属性表示了一个硬性约束:车辆承载的负载不得超过指定类型的 maxLoad
值。softMaxLoad
和 costPerUnitAboveSoftMax
属性表示一种软约束,每个超过 softMaxLoad
的单位都会产生 costPerUnitAboveSoftMax
费用。
软负载限制限制条件有多种用途,例如:
- 平衡车辆数量,超过最低数量要求的车辆(如果这样做具有成本效益)
- 让司机对特定航线能舒适地取货和送餐的偏好程度
- 将车辆装入低于其最大物理容量的车辆,以限制磨损并降低维护成本
硬负载限制和软负载限制可结合使用。例如,硬性载重限制可以表示车辆可安全携带的货物的最大重量或一次可装在一辆车中的最大物品数量,而软载重限制可以表示对驾驶员在装在车辆中的所有物品造成影响的最大重量或物品数量。