本指南將說明 loadDemands
和 loadLimits
,以及兩者之間的關係。
如「取貨和運送時間視窗限制」一文所述,OptimizeToursRequest
訊息 (REST、gRPC) 包含許多屬性,可以針對正在最佳化的問題指定限制。多個 OptimizeToursRequest
屬性代表「載入限制」。
車輛和貨運具有實體屬性,在規劃路線時必須納入考量。
- 車輛:
loadLimits
屬性會指定車輛可處理的最大負載量。請參閱Vehicle
訊息的 (REST、gRPC) 說明文件。 - 出貨:
loadDemands
屬性會指定特定出貨商品的承載量。請參閱Shipment
訊息的 (REST、gRPC) 說明文件。
透過這兩個限制,最佳化器可以依據您的機群容量和運送需求,以最符合車隊容量和運送需求的方式,正確為車輛指派貨物。
本文件的其餘部分將詳細說明 loadLimits
和 loadDemands
。
載入需求和限制:類型
您可以利用類型來表示每個載入需求和限制限制。
您可以提供自己的載入類型組合,如下列範例所示:
- 重量
- 磁碟區
- 線性測量
- 所運送物品或設備的名稱
本指南使用 weightKg
做為範例類型。
Shipment.loadDemands
和 Vehicle.loadLimits
都使用通訊協定緩衝區 map
類型,其中 string
鍵代表載入類型。
Shipment.loadDemands
值使用 Load
訊息 (REST、gRPC)。Load
訊息有一個單一 amount
屬性,代表完成指定類型運送所需的容量。
Vehicle.loadLimits
值使用 LoadLimit
訊息 (REST、gRPC)。LoadLimit
訊息有多個屬性,其中 maxLoad
代表車輛在指定類型中的最大負載量。
只有兩者的載入類型鍵相符時,運送的 loadDemands
才會使用指派車輛的 loadLimits
。舉例來說,loadDemands
的配送為:
"loadDemands": {
"weightKg": {
"amount": 50
}
}
需要 50 個 weightKg
類型載入單位才能完成出貨。loadLimits
的車輛:
"loadLimits": {
"weightKg": {
"maxLoad": 100
}
}
因為車輛在 weightKg
類型的 maxLoad
大於或等於 weightKg
類型中的運送 loadDemands
,因此可完成運送。不過,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]
的載入需求為 50weightKg
。shipments[1]
的載入需求為 10weightKg
。shipments[2]
的載入需求為 80weightKg
。vehicles[0]
的載入上限為 100weightKg
。
查看要求的回應與載入需求和限制
{ "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
完成後車輛載入量的變化。正載入值代表運送負載,負值則代表出貨中卸載。
每個 transitions
項目都包含 Transition
期間的車輛總負載量。舉例來說,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
費用。
軟載入限制限制有數種用途,例如:
- 平衡載客的車輛數量若超過所需最低數量 如果相當符合成本效益
- 表示駕駛人在指定路線上能舒適自取和外送的商品數量
- 將車輛負載增加至低於實體容量上限,藉此降低車輛消耗和維護成本
您可以同時使用硬負載和軟負載限制。舉例來說,硬載限制可能會表示車輛可以安全攜帶的車量上限,或車輛一次可容納的車輛數量上限,而軟負載限制可能是導致駕駛人能容納所有車內物品的最大重量或物品數量。