集荷と配送の停車場所注文の基本的な最適化

このシナリオでは、単純な費用パラメータを使用して、車両に割り当てられた停留所の順序を最適化します。これはルート最適化オペレーションの最もシンプルなモードであり、指定された時間内にすべての停留所を訪問します。

次の例は、1 台の車両と 3 件の配送を含む基本的なシナリオを示しています。これらはすべて、デポと呼ばれる単一のロケーションから発送されます。

リクエストの例

      {
        "populatePolylines": true,
        "populateTransitionPolylines": true,
        "model": {
          "globalStartTime": "2023-01-13T16:00:00-08:00",
          "globalEndTime": "2023-01-14T16:00:00-08:00",
          "shipments": [
            {
              "deliveries": [
                {
                  "arrivalLocation": {
                    "latitude": 37.789456,
                    "longitude": -122.390192
                  },
                  "duration": "250s"
                }
              ],
              "pickups": [
                {
                  "arrivalLocation": {
                    "latitude": 37.794465,
                    "longitude": -122.394839
                  },
                  "duration": "150s"
                }
              ]
            },
            {
              "deliveries": [
                {
                  "arrivalLocation": {
                    "latitude": 37.789116,
                    "longitude": -122.395080
                  },
                  "duration": "250s"
                }
              ],
              "pickups": [
                {
                  "arrivalLocation": {
                    "latitude": 37.794465,
                    "longitude": -122.394839
                  },
                  "duration": "150s"
                }
              ]
            },
            {
              "deliveries": [
                {
                  "arrivalLocation": {
                    "latitude": 37.795242,
                    "longitude": -122.399347
                  },
                  "duration": "250s"
                }
              ],
              "pickups": [
                {
                  "arrivalLocation": {
                    "latitude": 37.794465,
                    "longitude": -122.394839
                  },
                  "duration": "150s"
                }
              ]
            }
          ],
          "vehicles": [
            {
              "endLocation": {
                "latitude": 37.794465,
                "longitude": -122.394839
              },
              "startLocation": {
                "latitude": 37.794465,
                "longitude": -122.394839
              },
              "costPerKilometer": 10.0,
              "costPerHour": 40.0
            }
          ]
        }
      }
    

ルート最適化リクエスト フィールド

概要で説明したように、ルート最適化リクエストで最も重要なプロパティは vehiclesshipments です。

リクエストには、車両と配送に加えて、次のフィールドが含まれます。

ポリライン

populatePolylinespopulateTransitionPolylines は、ルート最適化でポリラインを返すかどうかを指定します。

このサービスは、Maps JS ポリライン コーデックを使用してポリラインをエンコードします。このコーデックは、印字可能な ASCII 文字を使用してバイナリ ポリライン データを表します。インタラクティブ ポリライン エンコーダー ユーティリティを使用すると、ルート最適化によって計算されたパスを可視化できます。このガイドの例では、populatePolylinespopulateTransitionPolylines を true に設定していますが、他のガイドでは、レスポンス サイズを小さくするために false に設定しています。

エンコード形式の詳細については、エンコード ポリライン アルゴリズム形式をご覧ください。

グローバルな時間制限

model.globalStartTimemodel.globalEndTime は任意の 24 時間に設定されます。これにより、出力のタイムスタンプを解釈しやすくなります。

場所を訪れる

このサンプル リクエストでは、model.shipments[].pickups[].arrivalLocationmodel.shipments[].deliveries[].arrivalLocation のみを使用しています。また、車両が到着地点とは異なる地点から出発する状況(建物の片側に駐車場があり、反対側に出口がある駐車場など)に対応する departureLocation プロパティもあります。このガイドと以降のガイドでは、到着地と出発地が同じであると想定しています。

latLng の代替として、到着と出発の waypoint もあります。Waypoint フィールドは、LatLng の代わりに Google プレイス ID を使用できます。また、車両の向きを指定することもできます。詳細については、リファレンス ドキュメント(RESTgRPC)をご覧ください。

例の制約

このシナリオでは、次のようないくつかの方法でオプティマイザーが制約されます。

  1. すべてのアクティビティは、グローバルな開始時間と終了時間の間に完了する必要があります。このシナリオでは、配送が近接しており、世界中の広い時間帯が対象であるため、開始時間と終了時間の制約は非常に緩やかです。
  2. すべての配送が完了している必要があります。これは、shipments にペナルティ費用が指定されていない場合のデフォルトの動作です。
  3. costPerKilometercostPerHour が車両に設定されている。

費用については、費用モデルのパラメータをご覧ください。

ルート最適化レスポンス プロパティ

サンプル リクエストへのレスポンスを確認する

    {
      "routes": [
        {
          "vehicleStartTime": "2023-01-14T00:00:00Z",
          "vehicleEndTime": "2023-01-14T00:36:41Z",
          "visits": [
            {
              "shipmentIndex": 2,
              "isPickup": true,
              "startTime": "2023-01-14T00:00:00Z",
              "detour": "0s"
            },
            {
              "shipmentIndex": 1,
              "isPickup": true,
              "startTime": "2023-01-14T00:02:30Z",
              "detour": "150s"
            },
            {
              "isPickup": true,
              "startTime": "2023-01-14T00:05:00Z",
              "detour": "300s"
            },
            {
              "startTime": "2023-01-14T00:11:25Z",
              "detour": "0s"
            },
            {
              "shipmentIndex": 1,
              "startTime": "2023-01-14T00:19:29Z",
              "detour": "503s"
            },
            {
              "shipmentIndex": 2,
              "startTime": "2023-01-14T00:29:02Z",
              "detour": "1324s"
            }
          ],
          "transitions": [
            {
              "travelDuration": "0s",
              "waitDuration": "0s",
              "totalDuration": "0s",
              "startTime": "2023-01-14T00:00:00Z",
              "routePolyline": {}
            },
            {
              "travelDuration": "0s",
              "waitDuration": "0s",
              "totalDuration": "0s",
              "startTime": "2023-01-14T00:02:30Z",
              "routePolyline": {}
            },
            {
              "travelDuration": "0s",
              "waitDuration": "0s",
              "totalDuration": "0s",
              "startTime": "2023-01-14T00:05:00Z",
              "routePolyline": {}
            },
            {
              "travelDuration": "235s",
              "travelDistanceMeters": 795,
              "waitDuration": "0s",
              "totalDuration": "235s",
              "startTime": "2023-01-14T00:07:30Z",
              "routePolyline": {
                "points": "kvteFtfjVAA?C?C@C?A?C@AFMj@s@JKb@k@Zc@LSjA}ARWDGdAxAdAvAXa@@k@AsA\\c@FKp@_A\\c@Ze@fA{ALSFGd@o@rAgBB{BZc@"
              }
            },
            {
              "travelDuration": "234s",
              "travelDistanceMeters": 793,
              "waitDuration": "0s",
              "totalDuration": "234s",
              "startTime": "2023-01-14T00:15:35Z",
              "routePolyline": {
                "points": "cwseFti_jVRWj@w@x@eAHLNRHJbApAHLX\\V^?@hA~AT\\PVFFDHDFJNp@~@NRLNNTFFUZIJY^Y^g@p@[`@KP{@fAEFSXe@l@c@h@WZY\\?BELk@v@MNa@l@"
              }
            },
            {
              "travelDuration": "323s",
              "travelDistanceMeters": 1204,
              "waitDuration": "0s",
              "totalDuration": "323s",
              "startTime": "2023-01-14T00:23:39Z",
              "routePolyline": {
                "points": "cuseFhjVSTY`@Yb@GHEDIJEF]f@IJi@r@oAbBeCfDKLaApAKNQVIPKPCDQJIBIBM@iAJeALqBVC@C?A?QBYDI@C?_@Dc@FO@a@FDp@HfAHvABVDl@Dj@PpCQDiALsALAQASKwAOgBEe@COCYEa@Es@Eg@"
              }
            },
            {
              "travelDuration": "209s",
              "travelDistanceMeters": 665,
              "waitDuration": "0s",
              "totalDuration": "209s",
              "startTime": "2023-01-14T00:33:12Z",
              "routePolyline": {
                "points": "{zteFxbajV?CAYEc@AMC_@AOAK?E?CCWAOAKCe@CY?WScDEm@d@EFA\\ENCB?XEVC^E`@EhBUVCNEB?@?\\Er@IMUe@k@k@w@AAMQa@i@SWQWMQi@u@AC?A"
              }
            }
          ],
          "routePolyline": {
            "points": "kvteFtfjVAA?C?C@C?A?C@AFMj@s@JKb@k@Zc@LSjA}ARWDGdAxAdAvAXa@@k@AsA\\c@FKp@_A\\c@Ze@fA{ALSFGd@o@rAgBB{BZc@RWj@w@x@eAHLNRHJbApAHLX\\V^?@hA~AT\\PVFFDHDFJNp@~@NRLNNTFFUZIJY^Y^g@p@[@KP{@fAEFSXe@l@c@h@WZY\\?BELk@v@MNa@l@STY@Yb@GHEDIJEF]f@IJi@r@oAbBeCfDKLaApAKNQVIPKPCDQJIBIBM@iAJeALqBVC@C?A?QBYDI@C?_@Dc@FO@a@FDp@HfAHvABVDl@Dj@PpCQDiALsALAQASKwAOgBEe@COCYEa@Es@Eg@?CAYEc@AMC_@AOAK?E?CCWAOAKCe@CY?WScDEm@d@EFA\\ENCB?XEVC^E`@EhBUVCNEB?@?\\Er@IMUe@k@k@w@AAMQa@i@SWQWMQi@u@AC?A"
          },
          "metrics": {
            "performedShipmentCount": 3,
            "travelDuration": "1001s",
            "waitDuration": "0s",
            "delayDuration": "0s",
            "breakDuration": "0s",
            "visitDuration": "1200s",
            "totalDuration": "2201s",
            "travelDistanceMeters": 3457
          },
          "travelSteps": [
            {
              "duration": "0s",
              "routePolyline": {}
            },
            {
              "duration": "0s",
              "routePolyline": {}
            },
            {
              "duration": "0s",
              "routePolyline": {}
            },
            {
              "duration": "227s",
              "distanceMeters": 794,
              "routePolyline": {
                "points": "kvteFtfjVAA?C?C@C?A?C@AFMj@s@JKb@k@Zc@LSjA}ARWDGdAxAdAvAXa@@k@AsA\\c@FKp@_A\\c@Ze@fA{ALSFGd@o@rAgBB{BZc@"
              }
            },
            {
              "duration": "233s",
              "distanceMeters": 791,
              "routePolyline": {
                "points": "cwseFti_jVRWj@w@x@eAHLNRHJbApAHLX\\V^?@hA~AT\\PVFFDHDFJNp@~@NRLNNTFFUZIJY^Y^g@p@[`@KP{@fAEFSXe@l@c@h@WZY\\?BELk@v@MNa@l@"
              }
            },
            {
              "duration": "322s",
              "distanceMeters": 1205,
              "routePolyline": {
                "points": "cuseFhjVSTY`@Yb@GHEDIJEF]f@IJi@r@oAbBeCfDKLaApAKNQVIPKPCDQJIBIBM@iAJeALqBVC@C?A?QBYDI@C?_@Dc@FO@a@FDp@HfAHvABVDl@Dj@PpCQDiALsALAQASKwAOgBEe@COCYEa@Es@Eg@"
              }
            },
            {
              "duration": "208s",
              "distanceMeters": 666,
              "routePolyline": {
                "points": "{zteFxbajV?CAYEc@AMC_@AOAK?E?CCWAOAKCe@CY?WScDEm@d@EFA\\ENCB?XEVC^E`@EhBUVCNEB?@?\\Er@IMUe@k@k@w@AAMQa@i@SWQWMQi@u@AC?A"
              }
            }
          ],
          "vehicleDetour": "2201s",
          "routeCosts": {
            "model.vehicles.cost_per_hour": 24.455555555555556,
            "model.vehicles.cost_per_kilometer": 34.57
          },
          "routeTotalCost": 59.025555555555556
        }
      ],
      "totalCost": 59.025555555555556,
      "metrics": {
        "aggregatedRouteMetrics": {
          "performedShipmentCount": 3,
          "travelDuration": "1001s",
          "waitDuration": "0s",
          "delayDuration": "0s",
          "breakDuration": "0s",
          "visitDuration": "1200s",
          "totalDuration": "2201s",
          "travelDistanceMeters": 3457
        },
        "usedVehicleCount": 1,
        "earliestVehicleStartTime": "2023-01-14T00:00:00Z",
        "latestVehicleEndTime": "2023-01-14T00:36:41Z",
        "totalCost": 59.025555555555556,
        "costs": {
          "model.vehicles.cost_per_kilometer": 34.57,
          "model.vehicles.cost_per_hour": 24.455555555555556
        }
      }
    }
    

ルート最適化レスポンスには、提案されたルートを表すトップレベルの routes フィールドが含まれます。車両ごとに 1 つのルートがあります。このガイドのサンプル リクエストでは車両を 1 台のみ指定しているため、routes には 1 つの ShipmentRoute メッセージが含まれます。

ShipmentRoute 件の宿泊施設

ShipmentRoute メッセージ タイプの最も重要なプロパティは、visitstransitions です。

Visit は、リクエスト メッセージの VisitRequest のいずれかからの集荷または配達の完了を表します。訪問は、車両が特定の場所と時間に完了する作業を割り当てていることになります。

Transition は、ある場所から別の場所に移動する車両を表します。車両の出発地、訪問地、車両のエンドポイントのペア間で遷移が発生することがあります。

車両のルートを完全に再構築するには、ShipmentRoutevisitstransitions を組み合わせる必要があります。車両のアクティビティの進行状況を示すフィールドの組み合わせは次のようになります。

request.vehicles[0].startLocation -> transitions[0] -> visits[0] ->
transitions[1] -> visits[1] -> transitions[2] -> ... -> visits[3] ->
transitions[4] -> request.vehicles[0].endLocation

車両はルートの開始地点から最初の訪問地点まで移動し、最後の訪問地点からルートの終点まで移動する必要があるため、ShipmentRoute には常に visits より 1 つ多くの transitions があります。車両に開始地点または終了地点がない場合、最初の訪問または最後の訪問の位置情報が車両の開始地点または終了地点として使用されるため、visits よりも transitions が 1 つ多くなります。

この例では、最初の 3 件の集荷訪問の間には、距離と所要時間がゼロの遷移があります。これは、3 件の集荷がすべてリクエストで同じ場所を共有しているためです。

詳細については、ShipmentRoute リファレンス ドキュメント(RESTgRPC)をご覧ください。

ウェイポイントの順序を簡単に最適化する

この例に示すように、Route Optimization は配送の属性として訪問地をモデル化し、独立したエンティティとしてのウェイポイントや停留所の概念はありません。ただし、停留所やウェイポイントを配送として表すことは可能です。その場合、集荷または配達として VisitRequest を 1 つだけ指定します。オプティマイザーが最適なルートを検索するには、車両に costPerHour または costPerKilometer を割り当てる必要があります(実行可能なルートを検索する場合とは異なります)。