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

Ten scenariusz optymalizuje kolejność przystanków przypisanych do pojazdu z prostymi parametrami dotyczącymi kosztów. Jest to najprostszy tryb działania optymalizacji trasy, który gwarantuje, że wszystkie przystanki zostaną odwiedzone w określonym czasie.

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 wspomnieliśmy w sekcji Omówienie, najważniejsze właściwości żądania optymalizacji trasy to vehicles i shipments.

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 zwizualizować ścieżki obliczone przez optymalizację trasy, możesz użyć interaktywnego kodera Polyline Encoder. W tym przykładzie wartości populatePolylinespopulateTransitionPolylines są ustawione na „PRAWDA”, ale w innych przewodnikach mają one wartość „FAŁSZ”, aby zmniejszyć rozmiar odpowiedzi.

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

Globalne ograniczenia czasowe

Aplikacje model.globalStartTime i model.globalEndTime są ustawione na dowolny 24-godzinny okres. Ułatwia to interpretację sygnatur czasowych wyjściowych.

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 innego niż to, z którego przyjechał, np. z parkingu, który ma wejście z jednej strony budynku, a wyjście z 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ą identyfikatory miejsc Google jako alternatywę dla LatLng. Można też określić kierunek jazdy pojazdu. Więcej informacji znajdziesz w dokumentacji referencyjnej (REST, gRPC).

Ograniczenia w przykładzie

Ten scenariusz ogranicza optymalizatora 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 działanie domyślne, gdy koszty karne nie są określone w shipments.
  3. costPerKilometer i costPerHour są ustawione w pojeździe.

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ź dotycząca optymalizacji trasy zawiera pole routes najwyższego poziomu reprezentujące proponowane trasy z jedną trasą dla każdego pojazdu. 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 ma być wykonane przez pojazd 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ą z zerową odległością i czasem, 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.