負載需求和限制

本指南將說明 loadDemandsloadLimits,以及兩者之間的關係。

如「取貨和運送時間視窗限制」一文所述,OptimizeToursRequest 訊息 (RESTgRPC) 包含許多屬性,可以針對正在最佳化的問題指定限制。多個 OptimizeToursRequest 屬性代表「載入限制」

車輛和貨運具有實體屬性,在規劃路線時必須納入考量。

  • 車輛loadLimits 屬性會指定車輛可處理的最大負載量。請參閱 Vehicle 訊息的 (RESTgRPC) 說明文件。
  • 出貨loadDemands 屬性會指定特定出貨商品的承載量。請參閱 Shipment 訊息的 (RESTgRPC) 說明文件。

透過這兩個限制,最佳化器可以依據您的機群容量和運送需求,以最符合車隊容量和運送需求的方式,正確為車輛指派貨物。

本文件的其餘部分將詳細說明 loadLimitsloadDemands

載入需求和限制:類型

您可以利用類型來表示每個載入需求和限制限制。

您可以提供自己的載入類型組合,如下列範例所示:

  • 重量
  • 磁碟區
  • 線性測量
  • 所運送物品或設備的名稱

本指南使用 weightKg 做為範例類型。

Shipment.loadDemandsVehicle.loadLimits 都使用通訊協定緩衝區 map 類型,其中 string 鍵代表載入類型。

Shipment.loadDemands 值使用 Load 訊息 (RESTgRPC)。Load 訊息有一個單一 amount 屬性,代表完成指定類型運送所需的容量。

Vehicle.loadLimits 值使用 LoadLimit 訊息 (RESTgRPC)。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 訊息 (RESTgRPC)routes.transitions 項目中,查看車輛的負載量。序列如下:

  1. 將貨物所需的負載量定義為 loadDemand
  2. 運送的商品會由指派的車輛接收,而車輛的 vehicleLoads 會增加運送的 loadDemand 數量。這項移轉作業會在回應訊息中以「正面」visits.loadDemands 表示。
  3. 車輛出貨,車輛的 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] 的載入需求為 10 weightKg
  • shipments[2] 的載入需求為 80 weightKg
  • 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 的順序:

  1. 已取車「shipment[0]
  2. 已取車「shipment[1]
  3. shipment[0]」已送達
  4. shipment[1]」已送達
  5. 已取車「shipment[2]
  6. shipment[2]」已送達

這筆訂單表示車輛無法同時完成三件出貨,因為其總 loadDemands 超過車輛的 loadLimits

每個 visits 項目都包含 Visit 完成後車輛載入量的變化。正載入值代表運送負載,負值則代表出貨中卸載。

每個 transitions 項目都包含 Transition 期間的車輛總負載量。舉例來說,transitions[2]weightKg 載入為 60,代表 shipment[0]shipment[1] 的合併載入。

指標物件 routes[0].metricsmetrics.aggregatedRouteMetrics 包含 maxLoads 屬性。weightKg 類型的值為 80,代表車輛路線中,將 shipments[2] 運送至運送地點的部分。

軟載入限制限制

與「取貨和運送時間視窗限制」一文所述的時間範圍相同,載入限制限制含有硬性和軟性變化版本。LoadLimit 訊息的 maxLoad 屬性表示有硬限制:車輛的負載不得超過指定類型中 maxLoad 值。softMaxLoadcostPerUnitAboveSoftMax 屬性表示軟性限制,每個單位超過 softMaxLoad 都會產生 costPerUnitAboveSoftMax 費用。

軟載入限制限制有數種用途,例如:

  • 平衡載客的車輛數量若超過所需最低數量 如果相當符合成本效益
  • 表示駕駛人在指定路線上能舒適自取和外送的商品數量
  • 將車輛負載增加至低於實體容量上限,藉此降低車輛消耗和維護成本

您可以同時使用硬負載和軟負載限制。舉例來說,硬載限制可能會表示車輛可以安全攜帶的車量上限,或車輛一次可容納的車輛數量上限,而軟負載限制可能是導致駕駛人能容納所有車內物品的最大重量或物品數量。