Podstawowa optymalizacja obsługi zamówień z odbiorem i dostawą

W tym scenariuszu kolejność przystanków przypisanych do pojazdu jest optymalizowana za pomocą prostych parametrów kosztu. Jest to najprostszy tryb działania optymalizacji trasy. Zapewnia, że wszystkie przystanki są odwiedzane w określonym przedziale czasu.

Ten przykład przedstawia podstawowy scenariusz z jednym pojazdem i 3 przesyłkami, które pochodzą z jednego miejsca zwanego depot.

Przykładowe żądanie

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

Pola żądania optymalizacji tras

Jak wspomniano w sekcji Omówienie, najważniejsze właściwości żądania usługi Route Optimization to vehiclesshipments.

Oprócz pojazdu i przesyłek prośba zawiera te pola:

Linie łamane

populatePolylinespopulateTransitionPolylines określają, czy optymalizacja trasy ma zwracać linie złożone.

Usługa koduje linie łamane za pomocą kodeka linii łamanych Maps JS, który reprezentuje binarne dane linii łamanej za pomocą drukowalnych znaków ASCII. Aby wizualizować ścieżki obliczone przez narzędzie Route Optimization, możesz użyć interaktywnej aplikacji do kodowania łańcuchów znaków. Przykład w tym przewodniku ustawia wartości populatePolylinespopulateTransitionPolylines na „prawda”, ale inne przewodniki ustawiają je na „fałsz”, aby zmniejszyć rozmiar odpowiedzi.

Opis formatu kodowania znajdziesz w artykule Encoded Polyline Algorithm Format (format algorytmu zakodowanej ścieżki).

Ograniczenia czasowe na całym świecie

Aplikacje model.globalStartTime i model.globalEndTime są ustawione na dowolny 24-godzinny okres. Dzięki temu łatwiej jest interpretować sygnały wyjściowe.

Odwiedź lokalizacje

W tym przykładzie żądaniu towarzyszą tylko parametry model.shipments[].pickups[].arrivalLocationmodel.shipments[].deliveries[].arrivalLocation. Dostępna jest też właściwość departureLocation, która służy do określania sytuacji, gdy pojazd odjeżdża z miejsca, do którego przyjechał, w innym miejscu niż to, z którego wyjeżdża, np. w przypadku kompleksu parkingowego z wejściem po jednej stronie budynku i wyjściem po drugiej. W tym i kolejnych przewodnikach punkty przyjazdu i odjazdu są takie same.

W zamian do latLng możesz też użyć wartości waypoint. Pola Waypoint obsługują identyfikatory miejsc Google jako alternatywę dla LatLng. Można też określić kierunek jazdy pojazdu. Aby dowiedzieć się więcej, zapoznaj się z odpowiednią dokumentacją (REST, gRPC).

Ograniczenia w przykładzie

W tym scenariuszu optymalizator jest ograniczony na kilka sposobów:

  1. Cała aktywność musi zostać ukończona w okresie globalnym między godzinami rozpoczęcia i zakończenia. W tym scenariuszu czasy rozpoczęcia i zakończenia są bardzo luźno określone ze względu na niewielką odległość między dostawami i szerokie okno czasowe na całym świecie.
  2. Wszystkie przesyłki muszą zostać zrealizowane. Jest to domyślne zachowanie, gdy koszty kary nie są określone w shipments.
  3. W pojazdzie są ustawione opcje costPerKilometercostPerHour.

Koszty są omawiane w sekcji Parametry modelu kosztowego.

Właściwości odpowiedzi usługi Optymalizacja tras

Zobacz odpowiedź na przykładowe zgłoszenie

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

Odpowiedź optymalizacji trasy zawiera pole najwyższego poziomu routes, które reprezentuje proponowane trasy, po jednej na pojazd. Ponieważ przykładowa prośba w tym przewodniku dotyczy tylko jednego pojazdu, routes zawiera jedną wiadomość ShipmentRoute.

ShipmentRoute miejsca zakwaterowania

Dwie najważniejsze właściwości w przypadku wiadomości typu ShipmentRoute to visitstransitions.

Każdy element Visit oznacza zakończenie odbioru lub dostawy z jednego z elementów VisitRequest wiadomości z prośbą. Wizyta to przydzielone zadanie, które pojazd ma wykonać w określonym miejscu i w określonym czasie.

Każdy element Transition reprezentuje pojazd przemieszczający się z jednej lokalizacji do następnej. Przejścia mogą występować między punktem początkowym pojazdu, miejscem wizyty i punktem końcowym.

Aby odtworzyć pełną trasę przejazdu pojazdu, należy połączyć visits i transitions.ShipmentRoute Połączenie pól w ramach sekwencji aktywności pojazdu wygląda tak:

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

W przypadku ShipmentRoute zawsze występuje o jeden transitions więcej niż w przypadku visits, ponieważ pojazd musi przejechać z miejsca początkowego do pierwszego przystanku na początku trasy i z ostatniego przystanku do miejsca docelowego na końcu trasy. Jeśli pojazd nie ma lokalizacji początkowej ani końcowej, będzie o jedną transitions więcej niż visits, ponieważ lokalizacja pierwszej lub ostatniej wizyty jest używana odpowiednio jako lokalizacja początkowa lub końcowa pojazdu.

W tym przykładzie pierwsze 3 przejazdy mają przejścia między sobą o zerowej odległości i czasie, ponieważ wszystkie 3 przejazdy mają tę samą lokalizację w żądaniu.

Aby dowiedzieć się więcej, zapoznaj się z dokumentacją referencyjną ShipmentRoute (REST, gRPC).

Prosta optymalizacja kolejności punktów pośrednich

Jak widać w tym przykładzie, model optymalizacji tras traktuje wizyty jako właściwości przesyłek i nie uwzględnia punktów pośrednich ani przystanków jako niezależnych elementów. Możliwe jest jednak przedstawienie przystanków lub punktów pośrednich jako przesyłek z dokładnie 1 VisitRequest jako odbiorem lub dostawą. Aby optymalizator mógł znaleźć optymalną trasę (a nie dowolną możliwą trasę), pojazd musi mieć przypisaną wartość costPerHour lub costPerKilometer.