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

Parametry populatePolylinespopulateTransitionPolylines określają, czy metoda RouteOptimization powinna 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 ścieżek wieloliniowych. Przykład w tym przewodniku ustawia parametry populatePolylinespopulateTransitionPolylines na wartość true, ale inne przewodniki ustawiają je na wartość false, aby zmniejszyć rozmiar odpowiedzi.

Opis formatu kodowania znajdziesz w artykule Encoded Polyline Algorithm Format (format algorytmu zakodowanej polilinii).

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ć sygnatury czasowe na wyjściu.

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 przyjechał, np. gdy kompleks parkingowy ma wejście po jednej stronie budynku, a wyjście po drugiej. W tym i kolejnych przewodnikach punkty przyjazdu i odjazdu są takie same.

Właściwości przyjazdu i wyjazdu waypoint są również dostępne jako alternatywa dla latLng. Pola Waypoint obsługują używanie identyfikatorów miejsc Google jako alternatywy 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 globalnego 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 długi okres globalny.
  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 optymalizacji 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

2 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ć ShipmentRoutevisits i transitions. 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.