Optimierung von Bestellungen zum Abholen und Liefern

In diesem Szenario wird die Reihenfolge der Stopps optimiert, die einem Fahrzeug mit einfachen Kostenparametern zugewiesen sind. Dies ist der einfachste Modus für die Routenoptimierung. Er sorgt dafür, dass alle Stopps innerhalb des angegebenen Zeitrahmens angefahren werden.

Das folgende Beispiel veranschaulicht ein einfaches Szenario mit einem Fahrzeug und drei Sendungen, die alle von einem einzigen Ort, einem Depot, ausgehen.

Beispielanfrage ansehen

      {
        "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
            }
          ]
        }
      }
    

Anfragefelder für Route Optimization

Wie in der Übersicht erwähnt, sind die wichtigsten Eigenschaften von Route Optimization-Anfragen vehicles und shipments.

Neben einem Fahrzeug und Sendungen enthält die Anfrage die folgenden Felder:

Polylinien

Mit populatePolylines und populateTransitionPolylines wird angegeben, ob für die Routenoptimierung Polylinien zurückgegeben werden sollen.

Der Dienst codiert Polylinien mit dem Maps JS-Polylinien-Codec, der binäre Polyliniendaten mit druckbaren ASCII-Zeichen darstellt. Mit dem interaktiven Dienstprogramm für die Codierung von Polylinien können Sie die von Route Optimization berechneten Routen visualisieren. Im Beispiel in diesem Leitfaden werden populatePolylines und populateTransitionPolylines auf „true“ gesetzt. In anderen Leitfäden werden sie auf „false“ gesetzt, um die Antwortgröße zu verringern.

Eine Beschreibung des Codierungsformats finden Sie unter Algorithmusformat für codierte Polylinien.

Globale Zeitbeschränkungen

model.globalStartTime und model.globalEndTime sind auf einen beliebigen 24-Stunden-Zeitraum festgelegt. Dadurch lassen sich die Zeitstempel der Ausgabe leichter interpretieren.

Standorte besuchen

In der Beispielanfrage werden nur model.shipments[].pickups[].arrivalLocation und model.shipments[].deliveries[].arrivalLocation verwendet. Außerdem gibt es die Eigenschaft departureLocation für Situationen, in denen das Fahrzeug an einem anderen Punkt abfährt als an dem, an dem es ankommt, z. B. bei einem Parkhaus mit einem Eingang auf der einen und einem Ausgang auf der anderen Seite des Gebäudes. In dieser und den folgenden Anleitungen wird davon ausgegangen, dass Ankunfts- und Abfahrtsort identisch sind.

„Ankunft“ und „Abreise“ waypoint sind auch als Alternative zu latLng verfügbar. In Waypoint-Feldern können Google-Orts-IDs als Alternative zu LatLng verwendet werden. Außerdem können Sie Fahrzeugüberschriften angeben. Weitere Informationen finden Sie in der Referenzdokumentation (REST, gRPC).

Einschränkungen im Beispiel

In diesem Szenario wird der Optimierer auf verschiedene Weise eingeschränkt:

  1. Alle Aktivitäten müssen zwischen den globalen Start- und Endzeiten abgeschlossen werden. In diesem Szenario sind Start- und Endzeiten aufgrund der Nähe der Sendungen und des großen globalen Zeitfensters eine sehr lockere Einschränkung.
  2. Alle Sendungen müssen abgeschlossen sein. Dies ist das Standardverhalten, wenn in shipments keine Strafkosten angegeben sind.
  3. costPerKilometer und costPerHour sind für das Fahrzeug festgelegt.

Die Kosten werden unter Parameter des Kostenmodells behandelt.

Antworteigenschaften für Route Optimization

Antwort auf die Beispielanfrage ansehen

    {
      "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
        }
      }
    }
    

Die Antwort zur Routenoptimierung enthält ein routes-Feld auf oberster Ebene, das die vorgeschlagenen Routen darstellt, wobei es eine Route pro Fahrzeug gibt. Da im Beispielanfrage in dieser Anleitung nur ein Fahrzeug angegeben ist, enthält routes eine ShipmentRoute-Nachricht.

ShipmentRoute Unterkünfte

Die beiden wichtigsten Attribute für den Nachrichtentyp ShipmentRoute sind visits und transitions.

Jede Visit steht für den Abschluss einer Abholung oder Lieferung von einem der VisitRequests der Anfragenachricht. Ein Besuch ist im Grunde eine Aufgabe, die von einem Fahrzeug an einem bestimmten Ort und zu einer bestimmten Zeit erledigt werden muss.

Jedes Transition steht für die Fahrt des Fahrzeugs von einem Ort zum nächsten. Übergänge können zwischen dem Startpunkt des Fahrzeugs, einem besuchten Ort und dem Endpunkt des Fahrzeugs auftreten.

Um die vollständige Route des Fahrzeugs zu rekonstruieren, müssen die ShipmentRoute-visits und transitions kombiniert werden. Die Kombination von Feldern zu einer Abfolge von Fahrzeugaktivitäten sieht so aus:

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

Eine ShipmentRoute hat immer ein transitions mehr als visits, da das Fahrzeug zu Beginn der Route von seinem Startort zum ersten Besuch und am Ende der Route vom letzten Besuch zu seinem Endort fahren muss. Wenn für das Fahrzeug kein Start- oder Endstandort angegeben ist, gibt es trotzdem ein transitions mehr als visits, da der Standort des ersten bzw. letzten Besuchs als Start- oder Endstandort des Fahrzeugs verwendet wird.

In diesem Beispiel haben die ersten drei Abholbesuche Übergänge mit einer Entfernung und Dauer von null, da alle drei Abholungen denselben Ort in der Anfrage haben.

Weitere Informationen finden Sie in der ShipmentRoute-Referenzdokumentation (REST, gRPC).

Einfache Optimierung der Wegpunktreihenfolge

Wie dieses Beispiel zeigt, werden Besuche in Modellen zur Routenoptimierung als Eigenschaften von Sendungen behandelt. Es gibt keine Wegpunkte oder Stopps als unabhängige Einheit. Es ist jedoch möglich, Haltestellen oder Wegpunkte als Sendungen mit genau einem VisitRequest als Abholung oder Zustellung darzustellen. Dem Fahrzeug muss weiterhin eine costPerHour oder costPerKilometer zugewiesen sein, damit der Optimierer eine optimale Route finden kann (im Gegensatz zu einer beliebigen möglichen Route).