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

Ten scenariusz optymalizuje kolejność przystanków przypisanych do pojazdu na podstawie prostych parametrów kosztów. Jest to najprostszy tryb działania funkcji Optymalizacji tras, który zapewnia odwiedzenie wszystkich przystanków w określonym przedziale czasu.

Poniższy przykład ilustruje podstawowy scenariusz z 1 pojazdem i 3 przesyłkami, które pochodzą z jednego miejsca zwanego depot.

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 tras

Jak wspomnieliśmy w omówieniu, najważniejsze właściwości żądania Optymalizacji tras to vehiclesshipments.

Oprócz pojazdu i przesyłek żądanie zawiera te pola:

Linie łamane

Parametry populatePolylinespopulateTransitionPolylines określają, czy Optymalizacja tras ma zwracać linie łamane.

Usługa koduje linie łamane za pomocą kodeka JavaScript linii łamanych w Mapach Google, który reprezentuje binarne dane linii łamanych w formie znaków ASCII możliwych do wydrukowania. Ścieżki obliczone przez funkcję Optymalizacji tras możesz wizualizować, korzystając z interaktywnego narzędzia do kodowania linii łamanych. W przykładzie w tym przewodniku wartości populatePolylinespopulateTransitionPolylines mają wartość „prawda”, ale w innych przewodnikach są ustawione na „fałsz” w celu zmniejszenia rozmiaru odpowiedzi.

Opis formatu kodowania znajdziesz w sekcji Format algorytmu zakodowanej linii łamanej.

Globalne ograniczenia czasowe

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

Odwiedzanie lokalizacji

Przykładowe żądanie używa tylko parametrów model.shipments[].pickups[].arrivalLocationmodel.shipments[].deliveries[].arrivalLocation. Istnieje także właściwość departureLocation do użycia w sytuacjach, gdy pojazd wyjeżdża z innego miejsca niż to, do którego przyjechał, np. w przypadku parkingu z wjazdem po jednej stronie budynku i wyjazdem po drugiej. W tym i kolejnych przewodnikach zakłada się, że punkty przyjazdu i odjazdu są takie same.

Właściwość waypoint przyjazdu i wyjazdu jest też dostępna jako alternatywa dla właściwości latLng. Pola Waypoint obsługują używanie identyfikatorów miejsc w Google jako alternatywy dla właściwości LatLng i mogą też określać kierunek jazdy pojazdu. Więcej informacji znajdziesz w dokumentacji (REST, gRPC).

Ograniczenia w przykładzie

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

  1. Wszystkie działania muszą zostać wykonane w okresie między globalną godziną rozpoczęcia a globalną godziną zakończenia. W tym scenariuszu godziny rozpoczęcia i zakończenia są bardzo luźnym ograniczeniem ze względu na bliskość miejsc dostaw przesyłek i długie globalne okno czasowe.
  2. Wszystkie dostawy muszą zostać zrealizowane. Jest to działanie domyślne, gdy w parametrze shipments nie określono kosztów kary.
  3. Parametry costPerKilometercostPerHour są ustawione w pojeździe.

Koszty są opisane w sekcji Parametry modelu kosztów.

Właściwości odpowiedzi Optymalizacji tras

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ź Optymalizacji tras zawiera pole routes najwyższego poziomu, które reprezentuje proponowane trasy, po jednej na pojazd. Ponieważ w przykładowym żądaniu w tym przewodniku został określony tylko 1 pojazd, pole routes zawiera 1 wiadomość ShipmentRoute.

Właściwości wiadomości ShipmentRoute

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

Każda właściwość Visit reprezentuje zrealizowanie odbioru lub dostawy z jednego z parametrów VisitRequest w wiadomości z żądaniem. Wizyta to przypisane zadanie, które pojazd ma wykonać w określonym miejscu i czasie.

Każda właściwość Transition oznacza pojazd przemieszczający się z jednej lokalizacji do drugiej. Przejazdy mogą występować między parą punktów: punktem początkowym pojazdu, lokalizacją wizyty i punktem końcowym pojazdu.

Aby odtworzyć pełną trasę pojazdu, należy połączyć właściwości visitstransitions wiadomości ShipmentRoute. Połączenie pól w ciąg 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

Wiadomość ShipmentRoute zawsze zawiera o 1 więcej właściwość transitions niż visits, ponieważ na początku trasy pojazd musi dojechać z lokalizacji początkowej do miejsca pierwszej wizyty, a na końcu trasy musi dojechać z miejsca ostatniej wizyty do lokalizacji końcowej. Jeśli pojazd nie ma określonej lokalizacji początkowej lub końcowej, nadal właściwości transitions będzie o 1 więcej niż visits, ponieważ jako lokalizacja początkowa lub końcowa pojazdu używana będzie odpowiednio lokalizacja pierwszej lub ostatniej wizyty.

W tym przykładzie przejazdy między 3 pierwszymi miejscami odbioru mają zerową odległość i czas trwania, ponieważ wszystkie 3 miejsca odbioru mają w żądaniu wskazaną tę samą lokalizację.

Więcej informacji znajdziesz w dokumentacji wiadomości ShipmentRoute (REST, gRPC).

Prosta optymalizacja kolejności punktów na trasie

Jak pokazuje ten przykład, Optymalizacja tras modeluje wizyty jako właściwości przesyłek i nie traktuje punktów pośrednich ani przystanków jako niezależnych encji. Można jednak przedstawić przystanki lub punkty pośrednie jako przesyłki z dokładnie jednym parametrem VisitRequest określającym odbiór lub dostawę. Aby optymalizator mógł znaleźć optymalną trasę (a nie tylko dowolną możliwą trasę), pojazd musi mieć określone parametry costPerHour lub costPerKilometer.