Optimierung von Bestellungen zum Abholen und Liefern

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

Das folgende Beispiel veranschaulicht ein grundlegendes Szenario mit einem Fahrzeug und drei Sendungen, die alle von einem einzigen Standort, dem sogenannten Depot, stammen.

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 Routenoptimierung

Wie in der Übersicht erwähnt, sind die wichtigsten Attribute der Anfrage zur Routenoptimierung vehicles und shipments.

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

Polylinien

Mit populatePolylines und populateTransitionPolylines wird angegeben, ob bei der Routenoptimierung Polylinien zurückgegeben werden sollen.

Der Dienst codiert Polylinien mithilfe des Maps JS-Polylinien-Codecs, der binäre Polyliniendaten mit druckbaren ASCII-Zeichen darstellt. Mit dem interaktiven Dienstprogramm für die Codierung von Polylinien können Sie die von der Routenoptimierung berechneten Pfade visualisieren. Im Beispiel in diesem Leitfaden werden populatePolylines und populateTransitionPolylines auf „true“ gesetzt, aber andere Führungslinien setzen sie auf „false“, um die Antwortgröße zu reduzieren.

Eine Beschreibung des Codierungsformats finden Sie unter Algorithmus für das Format codierter Polylinien.

Globale Zeitbeschränkungen

model.globalStartTime und model.globalEndTime sind auf einen beliebigen 24-Stunden-Zeitraum festgelegt. Dadurch sind Ausgabezeitstempel leichter zu interpretieren.

Orte besuchen

In der Beispielanfrage werden nur model.shipments[].pickups[].arrivalLocation und model.shipments[].deliveries[].arrivalLocation verwendet. Es gibt auch die Property departureLocation für Situationen, in denen das Fahrzeug an einem anderen Punkt abfährt als an der Ankunftspunkt, z. B. bei einem Parkplatz mit einem Eingang auf einer Seite des Gebäudes und einem Ausgang auf einer anderen Seite. Bei dieser und den nachfolgenden Reiseführern wird davon ausgegangen, dass die Ankunfts- und Startpunkte identisch sind.

Die Ankunfts- und Abfahrtszeiten „waypoint“ sind auch als Alternative zu latLng verfügbar. Waypoint-Felder unterstützen die Verwendung von Google Place-IDs als Alternative zu LatLng und können auch Fahrzeugrichtungen angeben. Weitere Informationen finden Sie in der Referenzdokumentation (REST, gRPC).

Einschränkungen im Beispiel

In diesem Szenario wird das Optimierungstool auf mehrere Arten eingeschränkt:

  1. Alle Aktivitäten müssen zwischen der globalen Start- und Endzeit abgeschlossen sein. In diesem Szenario sind die Start- und Endzeiten angesichts der Nähe der Lieferungen und des weiten globalen Zeitfensters eine sehr laxe 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 am Fahrzeug eingestellt.

Kosten werden unter Kostenmodellparameter behandelt.

Antwortattribute für die Routenoptimierung

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 der Routenoptimierung enthält ein übergeordnetes Feld routes, das die vorgeschlagenen Routen mit einer Route pro Fahrzeug darstellt. Da in der Beispielanfrage in diesem Leitfaden 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.

Jedes Visit steht für den Abschluss einer Abholung oder Zustellung aus einer der VisitRequests der Anfragenachricht. Einem Besuch wird effektiv Arbeit zugewiesen, die an einem bestimmten Ort und zu einer bestimmten Zeit von einem Fahrzeug erledigt werden muss.

Jedes Transition steht für das Fahrzeug, das von einem Standort zum nächsten fährt. Übergänge können zwischen zwei Startpunkten, einem Besuchsort und dem Endpunkt des Fahrzeugs erfolgen.

Um die vollständige Route des Fahrzeugs zu rekonstruieren, müssen die visits und die transitions der ShipmentRoute kombiniert werden. Die Kombination von Feldern in einem Verlauf der Fahrzeugaktivität 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

Ein ShipmentRoute hat immer einen transitions mehr als visits, da das Fahrzeug von seinem Startort bis zu seinem ersten Besuch am Anfang der Route und von seinem letzten Besuch bis zum Ziel am Ende der Route fahren muss. Wenn das Fahrzeug keinen Start- oder Zielpunkt hat, ist immer noch eine transitions als visits vorhanden, da der Standort des ersten oder letzten Besuchs als Start- bzw. Zielpunkt des Fahrzeugs verwendet wird.

In diesem Beispiel haben die ersten drei Abholbesuche Übergänge ohne Entfernung und Dauer, da alle drei Abholorte denselben Ort in der Anfrage haben.

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

Einfache Optimierung der Wegpunktreihenfolge

Wie in diesem Beispiel gezeigt, modelliert die Routenoptimierung Besuche als Attribute von Lieferungen. Wegpunkte oder Haltestellen werden nicht als unabhängige Entität definiert. Es ist jedoch möglich, Haltestellen oder Wegpunkte als Sendungen mit genau einer VisitRequest als Abhol- oder Lieferadresse darzustellen. Dem Fahrzeug muss immer noch eine costPerHour oder costPerKilometer zugewiesen werden, damit das Optimierungstool eine optimale Route findet (anstatt eine praktikable Route zu finden).