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.

Poniższy przykład ilustruje podstawowy scenariusz z jednym pojazdem i 3 przesyłkami, z których wszystkie pochodzą z jednej lokalizacji zwanej depozytem.

Zobacz 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 trasy

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 żądanie zawiera te pola:

Linie łamane

populatePolylines i populateTransitionPolylines określają, czy optymalizacja trasy ma zwracać linie łamane.

Usługa koduje linie łamane za pomocą kodeka linii łamanych Maps JS, który reprezentuje dane binarnej linii łamanej przy użyciu możliwych do wydrukowania znaków ASCII. Aby zwizualizować ścieżki obliczone przez optymalizację trasy, możesz użyć interaktywnego kodera Polyline Encoder. Przykład w tym przewodniku ustawia wartość populatePolylines i populateTransitionPolylines na wartość true, ale inne przewodniki mają ustawioną wartość Fałsz, co zmniejsza rozmiar odpowiedzi.

Opis formatu kodowania znajdziesz w sekcji Format algorytmu łamanego zakodowanego.

Globalne ograniczenia czasowe

model.globalStartTime i model.globalEndTime mają ustawiony dowolny okres 24-godzinny. Ułatwia to interpretację sygnatur czasowych wyjściowych.

Odwiedź lokalizacje

W przykładowym żądaniu są używane tylko właściwości model.shipments[].pickups[].arrivalLocation i model.shipments[].deliveries[].arrivalLocation. Istnieje również właściwość departureLocation obowiązująca w sytuacjach, gdy pojazd wyjeżdża z innego miejsca niż przyjechał, np. w parkingu z wejściem po jednej stronie budynku, a wyjściem z drugiej. W tym i kolejnych przewodnikach punkty przyjazdu i wyjazdu są takie same.

Przyjazd i wylot waypoint jest również alternatywą dla latLng. Pola Waypoint obsługują identyfikatory Miejsc Google jako alternatywę dla pola LatLng i mogą też określać nagłówki pojazdów. 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 być wykonana między globalnym czasem rozpoczęcia a zakończeniem. W tym scenariuszu czas rozpoczęcia i zakończenia jest bardzo rygorystycznym ograniczeniem ze względu na bliskość bliskości dostawy i szerokiego globalnego przedziału czasu.
  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ą określone w parametrach modelu kosztu.

Właściwości odpowiedzi na potrzeby optymalizacji trasy

Wyświetlanie odpowiedzi na przykładowe żądanie

    {
      "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. Przykładowe żądanie w tym przewodniku dotyczy tylko 1 pojazdu, dlatego routes zawiera 1 komunikat ShipmentRoute.

ShipmentRoute miejsca zakwaterowania

Dwie najważniejsze właściwości typu wiadomości ShipmentRoute to visits i transitions.

Każdy znak Visit oznacza zakończenie odbioru lub dostawy z jednego z VisitRequest wiadomości z prośbą. Wizyta to w praktyce przydzielane miejsce i czas do wykonania przez pojazd.

Każdy symbol Transition oznacza pojazd podróżujący z jednej lokalizacji do następnej. Przejścia mogą wystąpić między parą punktu początkowego pojazdu, lokalizacji wizyty i punktu końcowego pojazdu.

Aby odtworzyć pełną trasę pojazdu, należy połączyć punkty visits i transitions na linii ShipmentRoute. Połączenie pól w postępach aktywności pojazdów 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

ShipmentRoute ma zawsze o 1 element transitions więcej niż visits, ponieważ pojazd musi dojechać z miejsca początkowego do pierwszego na początku trasy, a od ostatniego do ostatniego miejsca na końcu trasy. Jeśli pojazd nie ma określonej lokalizacji początkowej lub końcowej, nadal będzie o 1 transitions więcej niż visits, ponieważ jako lokalizacja początkowa lub końcowa pojazdu używana jest odpowiednio lokalizacja dotycząca pierwszej lub ostatniej wizyty.

W tym przykładzie w przypadku pierwszych 3 wizyt z odbiorem występują między nimi przejścia z zerową odległością i czasem trwania, ponieważ wszystkie 3 punkty odbioru znajdują się w tej samej lokalizacji w żądaniu.

Więcej informacji znajdziesz w dokumentacji referencyjnej ShipmentRoute (REST, gRPC).

Prosta optymalizacja kolejności punktów pośrednich

Ten przykład pokazuje, że modele optymalizacji trasy wizyty są właściwościami statków i nie mają pojęcia punktów na trasie ani przystanków jako niezależnej jednostki. Przystanki lub punkty na trasie mogą jednak być przedstawiane jako przesyłki z jednym atrybutem VisitRequest jako odbiór lub dostawa. Pojazd nadal musi mieć przypisaną costPerHour lub costPerKilometer, aby optymalizator mógł wybrać optymalną trasę (zamiast znaleźć jakąkolwiek możliwą trasę).