OptimizeToursRequest
stosuje ograniczenia do tych elementów:
- Przesyłki, które wpływają na sposób realizacji dostaw
- Pojazdy, które mają wpływ na sposób obliczania tras pojazdów
- Dotyczy globalnie dotyczy zarówno pojazdów, jak i ładunków.
Ten przewodnik dotyczy zasadniczego ograniczenia dostawy: przedziałów czasowych.
Przedziały czasu to rodzaj ograniczeń, które podajesz w
OptimizeToursRequest
(REST, gRPC) do określenia
ograniczenia czasowe w działaniach związanych z dostawą. Ten typ ograniczenia wpływa
czas i sposób wysyłki oraz przypisanie pojazdu
za dostawę. Przy tych ograniczeniach optymalizator daje pierwszeństwo
tych pojazdów, które najlepiej spełnią wymagania czasowe dostawy.
Ograniczenia dostawy: przedziały czasowe
W wiadomości Shipment.VisitRequest
określasz, kiedy może nastąpić odbiór lub dostawa:
- Użyj w wiadomości właściwości
timeWindows
(REST, gRPC). - Określ czas rozpoczęcia i zakończenia w komunikacie
TimeWindow
(REST, gRPC).
Przykładowe żądanie z ograniczeniami przedziałów czasowych
Przykład pokazuje 3 różne przesyłki, z których każda ma własny przedział dostawy. Dla uproszczenia ten przykład ustawia przedziały czasowe w trybie deliveries
.
ale przedziały czasowe można też zastosować do odbioru. Wiele przedziałów czasu
został określony, ale w tym przykładzie użyto tylko jednego na przesłanie elementu VisitRequest
.
Zobacz przykładowe żądanie z przedziałami czasu
{ "populatePolylines": false, "populateTransitionPolylines": false, "model": { "globalStartTime": "2023-01-13T16:00:00Z", "globalEndTime": "2023-01-14T16:00:00Z", "shipments": [ { "deliveries": [ { "arrivalLocation": { "latitude": 37.789456, "longitude": -122.390192 }, "duration": "250s", "timeWindows": [ { "startTime": "2023-01-13T18:00:00Z", "endTime": "2023-01-13T19:00:00Z" } ] } ], "pickups": [ { "arrivalLocation": { "latitude": 37.794465, "longitude": -122.394839 }, "duration": "150s" } ], "penaltyCost": 100.0 }, { "deliveries": [ { "arrivalLocation": { "latitude": 37.789116, "longitude": -122.395080 }, "duration": "250s", "timeWindows": [ { "startTime": "2023-01-13T18:00:00Z", "endTime": "2023-01-13T18:30:00Z" } ] } ], "pickups": [ { "arrivalLocation": { "latitude": 37.794465, "longitude": -122.394839 }, "duration": "150s" } ], "penaltyCost": 20.0 }, { "deliveries": [ { "arrivalLocation": { "latitude": 37.795242, "longitude": -122.399347 }, "duration": "250s", "timeWindows": [ { "startTime": "2023-01-13T17:30:00Z", "endTime": "2023-01-13T18:00:00Z" } ] } ], "pickups": [ { "arrivalLocation": { "latitude": 37.794465, "longitude": -122.394839 }, "duration": "150s" } ], "penaltyCost": 50.0 } ], "vehicles": [ { "endLocation": { "latitude": 37.794465, "longitude": -122.394839 }, "startLocation": { "latitude": 37.794465, "longitude": -122.394839 }, "costPerHour": 40.0, "costPerKilometer": 10.0 } ] } }
Przykład odpowiedzi z ograniczeniami dotyczącymi przedziału czasowego
W przykładowej odpowiedzi czas rozpoczęcia i zakończenia pojazdu to godzina 17:35:50.
18:17:24. Te godziny oznaczają, że optymalizator minimalizuje czas.
wymagane do sterowania pojazdem określonym w żądaniu jako costPerHour
podczas
spełniając wszystkie ograniczenia przedziałów czasowych. Użycie godziny 17:35:50 jako godziny rozpoczęcia eliminuje konieczność oczekiwania pojazdu w miejscu wizyty do czasu rozpoczęcia okna czasowego wizyty. Ta wartość jest wyświetlana w odpowiedzi jako zero waitDuration
.
Wyświetl odpowiedź na przykładowe żądanie z przedziały czasowe
{ "routes": [ { "vehicleStartTime": "2023-01-13T17:35:50Z", "vehicleEndTime": "2023-01-13T18:17:24Z", "visits": [ { "isPickup": true, "startTime": "2023-01-13T17:35:50Z", "detour": "0s" }, { "shipmentIndex": 1, "isPickup": true, "startTime": "2023-01-13T17:38:20Z", "detour": "150s" }, { "shipmentIndex": 2, "isPickup": true, "startTime": "2023-01-13T17:40:50Z", "detour": "300s" }, { "shipmentIndex": 2, "startTime": "2023-01-13T17:50:09Z", "detour": "0s" }, { "shipmentIndex": 1, "startTime": "2023-01-13T18:00:00Z", "detour": "796s" }, { "startTime": "2023-01-13T18:07:35Z", "detour": "1520s" } ], "transitions": [ { "travelDuration": "0s", "waitDuration": "0s", "totalDuration": "0s", "startTime": "2023-01-13T17:35:50Z" }, { "travelDuration": "0s", "waitDuration": "0s", "totalDuration": "0s", "startTime": "2023-01-13T17:38:20Z" }, { "travelDuration": "0s", "waitDuration": "0s", "totalDuration": "0s", "startTime": "2023-01-13T17:40:50Z" }, { "travelDuration": "409s", "travelDistanceMeters": 1371, "waitDuration": "0s", "totalDuration": "409s", "startTime": "2023-01-13T17:43:20Z" }, { "travelDuration": "341s", "travelDistanceMeters": 1312, "waitDuration": "0s", "totalDuration": "341s", "startTime": "2023-01-13T17:54:19Z" }, { "travelDuration": "205s", "travelDistanceMeters": 636, "waitDuration": "0s", "totalDuration": "205s", "startTime": "2023-01-13T18:04:10Z" }, { "travelDuration": "339s", "travelDistanceMeters": 1276, "waitDuration": "0s", "totalDuration": "339s", "startTime": "2023-01-13T18:11:45Z" } ], "metrics": { "performedShipmentCount": 3, "travelDuration": "1294s", "waitDuration": "0s", "delayDuration": "0s", "breakDuration": "0s", "visitDuration": "1200s", "totalDuration": "2494s", "travelDistanceMeters": 4595 }, "routeCosts": { "model.vehicles.cost_per_hour": 27.711111111111112, "model.vehicles.cost_per_kilometer": 45.95 }, "routeTotalCost": 73.661111111111111 } ], "metrics": { "aggregatedRouteMetrics": { "performedShipmentCount": 3, "travelDuration": "1294s", "waitDuration": "0s", "delayDuration": "0s", "breakDuration": "0s", "visitDuration": "1200s", "totalDuration": "2494s", "travelDistanceMeters": 4595 }, "usedVehicleCount": 1, "earliestVehicleStartTime": "2023-01-13T17:35:50Z", "latestVehicleEndTime": "2023-01-13T18:17:24Z", "totalCost": 73.661111111111111, "costs": { "model.vehicles.cost_per_hour": 27.711111111111112, "model.vehicles.cost_per_kilometer": 45.95 } } }
Okna czasowe zamówiły pojazd visits
, więc przesyłki z najniższymi oknami czasowymi zostaną dostarczone jako pierwsze.
shipments[2]
jest dostarczany o 17:50shipments[1]
jest dostarczany o 18:00shipments[0]
jest dostarczany o 18:07
W przykładowym żądaniu określono sztywne ograniczenia przedziałów czasowych, które wymagają
realizacji zamówień w tych przedziałach czasowych. Jeśli Twoja przesyłka jest
VisitRequests
w dowolnym przedziale czasu jest niewykonalne lub
w sposób ekonomiczny, optymalizator pomija dostawę. Jeśli przesyłka ma
penaltyCost
, optymalizator dodaje ją do kosztów raportowanych w odpowiedzi
metrics
W przeciwnym razie właściwość skippedMandatoryShipmentCount
klucza
Komunikat OptimizeToursResponse
(REST, gRPC) wzrasta.
Jeśli zmienisz przedziały czasowe, przesuwając okno użytkownika shipment[1]
o kilka godzin
(do godz. 21:00 z 18:00) wyniki będą inne, co pokazano w
z poniższych przykładów.
Zobacz przykładowe żądanie z przedziałami czasu, których nie można satysfakcjonuje
{ "populatePolylines": false, "populateTransitionPolylines": false, "model": { "globalStartTime": "2023-01-13T16:00:00Z", "globalEndTime": "2023-01-14T16:00:00Z", "shipments": [ { "deliveries": [ { "arrivalLocation": { "latitude": 37.789456, "longitude": -122.390192 }, "duration": "250s", "timeWindows": [ { "startTime": "2023-01-13T18:00:00Z", "endTime": "2023-01-13T19:00:00Z" } ] } ], "pickups": [ { "arrivalLocation": { "latitude": 37.794465, "longitude": -122.394839 }, "duration": "150s" } ], "penaltyCost": 100.0 }, { "deliveries": [ { "arrivalLocation": { "latitude": 37.789116, "longitude": -122.395080 }, "duration": "250s", "timeWindows": [ { "startTime": "2023-01-13T21:00:00Z", "endTime": "2023-01-13T21:30:00Z" } ] } ], "pickups": [ { "arrivalLocation": { "latitude": 37.794465, "longitude": -122.394839 }, "duration": "150s" } ], "penaltyCost": 20.0 }, { "deliveries": [ { "arrivalLocation": { "latitude": 37.795242, "longitude": -122.399347 }, "duration": "250s", "timeWindows": [ { "startTime": "2023-01-13T17:30:00Z", "endTime": "2023-01-13T18:00:00Z" } ] } ], "pickups": [ { "arrivalLocation": { "latitude": 37.794465, "longitude": -122.394839 }, "duration": "150s" } ], "penaltyCost": 50.0 } ], "vehicles": [ { "endLocation": { "latitude": 37.794465, "longitude": -122.394839 }, "startLocation": { "latitude": 37.794465, "longitude": -122.394839 }, "costPerHour": 40.0, "costPerKilometer": 10.0 } ] } }
Możesz zobaczyć odpowiedź na drugie przykładowe żądanie, używając: przedziały czasowe, w których dostawa jest pomijana
{ "routes": [ { "vehicleStartTime": "2023-01-13T17:37:49Z", "vehicleEndTime": "2023-01-13T18:09:49Z", "visits": [ { "isPickup": true, "startTime": "2023-01-13T17:37:49Z", "detour": "0s" }, { "shipmentIndex": 2, "isPickup": true, "startTime": "2023-01-13T17:40:19Z", "detour": "150s" }, { "shipmentIndex": 2, "startTime": "2023-01-13T17:49:38Z", "detour": "0s" }, { "startTime": "2023-01-13T18:00:00Z", "detour": "946s" } ], "transitions": [ { "travelDuration": "0s", "waitDuration": "0s", "totalDuration": "0s", "startTime": "2023-01-13T17:37:49Z" }, { "travelDuration": "0s", "waitDuration": "0s", "totalDuration": "0s", "startTime": "2023-01-13T17:40:19Z" }, { "travelDuration": "409s", "travelDistanceMeters": 1371, "waitDuration": "0s", "totalDuration": "409s", "startTime": "2023-01-13T17:42:49Z" }, { "travelDuration": "372s", "travelDistanceMeters": 1348, "waitDuration": "0s", "totalDuration": "372s", "startTime": "2023-01-13T17:53:48Z" }, { "travelDuration": "339s", "travelDistanceMeters": 1276, "waitDuration": "0s", "totalDuration": "339s", "startTime": "2023-01-13T18:04:10Z" } ], "metrics": { "performedShipmentCount": 2, "travelDuration": "1120s", "waitDuration": "0s", "delayDuration": "0s", "breakDuration": "0s", "visitDuration": "800s", "totalDuration": "1920s", "travelDistanceMeters": 3995 }, "routeCosts": { "model.vehicles.cost_per_kilometer": 39.95, "model.vehicles.cost_per_hour": 21.333333333333332 }, "routeTotalCost": 61.283333333333331 } ], "skippedShipments": [ { "index": 1 } ], "metrics": { "aggregatedRouteMetrics": { "performedShipmentCount": 2, "travelDuration": "1120s", "waitDuration": "0s", "delayDuration": "0s", "breakDuration": "0s", "visitDuration": "800s", "totalDuration": "1920s", "travelDistanceMeters": 3995 }, "usedVehicleCount": 1, "earliestVehicleStartTime": "2023-01-13T17:37:49Z", "latestVehicleEndTime": "2023-01-13T18:09:49Z", "totalCost": 81.283333333333331, "costs": { "model.shipments.penalty_cost": 20, "model.vehicles.cost_per_hour": 21.333333333333332, "model.vehicles.cost_per_kilometer": 39.95 } } }
W tym przykładzie późniejsze okno spowodowało pominięcie elementu shipment[1]
,
ponieważ dodatkowy czas obsługi pojazdu niezbędny do
dostawa w określonym przedziale czasu przekroczyła koszt kary tej przesyłki.
Koszt kary dla kraju shipment[1]
pojawia się w metrics.costs
i jego indeksie
pojawia się w kolekcji skippedShipments
.
Miękkie ograniczenia dotyczące przedziału czasu
Jak krótko wspomniano w sekcji Parametry modelu kosztowego, okna czasowe mogą być stosowane jako miękkie ograniczenia. Ograniczenia miękkie różnią się od ograniczeń sztywnych w ten sposób:
- Twarde ograniczenia: nie można go naruszyć, a optymalizator nie oferuje naruszającego ograniczenie, nawet jeśli oznacza to pominięcie przesyłki.
- Ograniczone ograniczenia: mogą zostać naruszone, co oznacza, że optymalizator może zapewni rozwiązanie, które narusza miękkie ograniczenie. Optymalizator powoduje też naliczanie kosztów w przypadku naruszenia zasad. Podajesz ten koszt jako dodatkową właściwość w oknie czasowym, zwykle jako koszt za godzinę w każdej godzinie przed lub po oknie czasowym, w którym występuje aktywność.
Okna czasowe są zmiękczone przez użycie softStartTime
lub softEndTime
zamiast startTime
lub endTime
oraz ustawienie costPerHourBeforeSoftStartTime
lub costPerHourAfterSoftEndTime
.
Używaj ograniczeń czasowych, gdy powinny mieć miejsce odbiór lub dostawa w określonym przedziale czasu, ale odbiór lub dostawa w tym okresie nie są jest to absolutnie wymagane. Możesz stosować jednocześnie sztywne i miękkie ograniczenia przedziału czasu na potrzeby określania celów biznesowych. Na przykład:
- Okno ograniczonego czasu: wskazuje godziny pracy klienta, np. Od 9:00 do 17:00.
- Okno czasowe dostawy: wskazuje termin dostawy lub odbioru, pasuje do powiadomienia wysłanego do klienta, na przykład od 9:00 do 13:00.
W tym przykładzie przesyłka, która została wcześniej pominięta, ze względu na czas okno rozpoczęcia się zbyt późno, jego ograniczenie czasu rozpoczęcia jest zmniejszane. Druga przesyłki mają swoje przedziały czasowe, godziny zakończenia też uległy skróceniu.
Przykład prośby z nieprzekraczalnymi i nieprzekraczanymi terminami
{ "populatePolylines": false, "populateTransitionPolylines": false, "model": { "globalStartTime": "2023-01-13T16:00:00Z", "globalEndTime": "2023-01-14T16:00:00Z", "shipments": [ { "deliveries": [ { "arrivalLocation": { "latitude": 37.789456, "longitude": -122.390192 }, "duration": "250s", "timeWindows": [ { "startTime": "2023-01-13T18:00:00Z", "softEndTime": "2023-01-13T19:00:00Z", "costPerHourAfterSoftEndTime": 2.0 } ] } ], "pickups": [ { "arrivalLocation": { "latitude": 37.794465, "longitude": -122.394839 }, "duration": "150s" } ], "penaltyCost": 100.0 }, { "deliveries": [ { "arrivalLocation": { "latitude": 37.789116, "longitude": -122.395080 }, "duration": "250s", "timeWindows": [ { "softStartTime": "2023-01-13T21:00:00Z", "endTime": "2023-01-13T21:30:00Z", "costPerHourBeforeSoftStartTime": 2.0 } ] } ], "pickups": [ { "arrivalLocation": { "latitude": 37.794465, "longitude": -122.394839 }, "duration": "150s" } ], "penaltyCost": 20.0 }, { "deliveries": [ { "arrivalLocation": { "latitude": 37.795242, "longitude": -122.399347 }, "duration": "250s", "timeWindows": [ { "startTime": "2023-01-13T17:30:00Z", "softEndTime": "2023-01-13T18:00:00Z", "costPerHourAfterSoftEndTime": 2.0 } ] } ], "pickups": [ { "arrivalLocation": { "latitude": 37.794465, "longitude": -122.394839 }, "duration": "150s" } ], "penaltyCost": 50.0 } ], "vehicles": [ { "endLocation": { "latitude": 37.794465, "longitude": -122.394839 }, "startLocation": { "latitude": 37.794465, "longitude": -122.394839 }, "costPerHour": 40.0, "costPerKilometer": 10.0 } ] } }
wyświetlić odpowiedź na przykładowe żądanie z twardymi i łagodne przedziały czasowe
{ "routes": [ { "vehicleStartTime": "2023-01-13T17:48:35Z", "vehicleEndTime": "2023-01-13T18:24:28Z", "visits": [ { "isPickup": true, "startTime": "2023-01-13T17:48:35Z", "detour": "0s" }, { "shipmentIndex": 1, "isPickup": true, "startTime": "2023-01-13T17:51:05Z", "detour": "150s" }, { "shipmentIndex": 2, "isPickup": true, "startTime": "2023-01-13T17:53:35Z", "detour": "300s" }, { "startTime": "2023-01-13T18:00:00Z", "detour": "300s" }, { "shipmentIndex": 1, "startTime": "2023-01-13T18:07:42Z", "detour": "493s" }, { "shipmentIndex": 2, "startTime": "2023-01-13T18:17:27Z", "detour": "873s" } ], "transitions": [ { "travelDuration": "0s", "waitDuration": "0s", "totalDuration": "0s", "startTime": "2023-01-13T17:48:35Z" }, { "travelDuration": "0s", "waitDuration": "0s", "totalDuration": "0s", "startTime": "2023-01-13T17:51:05Z" }, { "travelDuration": "0s", "waitDuration": "0s", "totalDuration": "0s", "startTime": "2023-01-13T17:53:35Z" }, { "travelDuration": "235s", "travelDistanceMeters": 795, "waitDuration": "0s", "totalDuration": "235s", "startTime": "2023-01-13T17:56:05Z" }, { "travelDuration": "212s", "travelDistanceMeters": 791, "waitDuration": "0s", "totalDuration": "212s", "startTime": "2023-01-13T18:04:10Z" }, { "travelDuration": "335s", "travelDistanceMeters": 1204, "waitDuration": "0s", "totalDuration": "335s", "startTime": "2023-01-13T18:11:52Z" }, { "travelDuration": "171s", "travelDistanceMeters": 665, "waitDuration": "0s", "totalDuration": "171s", "startTime": "2023-01-13T18:21:37Z" } ], "metrics": { "performedShipmentCount": 3, "travelDuration": "953s", "waitDuration": "0s", "delayDuration": "0s", "breakDuration": "0s", "visitDuration": "1200s", "totalDuration": "2153s", "travelDistanceMeters": 3455 }, "routeCosts": { "model.shipments.deliveries.time_windows.cost_per_hour_after_soft_end_time": 0.58166666666666667, "model.shipments.deliveries.time_windows.cost_per_hour_before_soft_start_time": 5.7433333333333332, "model.vehicles.cost_per_hour": 23.922222222222221, "model.vehicles.cost_per_kilometer": 34.55 }, "routeTotalCost": 64.797222222222217 } ], "metrics": { "aggregatedRouteMetrics": { "performedShipmentCount": 3, "travelDuration": "953s", "waitDuration": "0s", "delayDuration": "0s", "breakDuration": "0s", "visitDuration": "1200s", "totalDuration": "2153s", "travelDistanceMeters": 3455 }, "usedVehicleCount": 1, "earliestVehicleStartTime": "2023-01-13T17:48:35Z", "latestVehicleEndTime": "2023-01-13T18:24:28Z", "totalCost": 64.797222222222217, "costs": { "model.vehicles.cost_per_kilometer": 34.55, "model.shipments.deliveries.time_windows.cost_per_hour_before_soft_start_time": 5.7433333333333332, "model.shipments.deliveries.time_windows.cost_per_hour_after_soft_end_time": 0.58166666666666667, "model.vehicles.cost_per_hour": 23.922222222222221 } } }
W którym przykład z całkowitymi ograniczeniami przedziałów czasowych
shipment[1]
, zmiękczenie czasu dostawy powoduje, że element jest dostarczany
przed czasem rozpoczęcia jego przedziału czasowego. Zmiękczenie terminów dostawy innych przesyłek pozwoliło na dostarczenie shipment[2]
po zakończeniu tego okna czasowego.
Jednocześnie zmieniły się zarówno koszty, jak i łączna liczba dostaw:
totalCost
: zmniejszono z 81.283 do 64,797- łączna liczba zrealizowanych dostaw: zwiększono z 2 do 3
Optymalizator znalazł tańsze rozwiązanie, ponieważ przedział czasu ograniczenia zostały złagodzone w porównaniu z poprzednim przykładem.
Właściwość metrics.costs
zawiera też nowy klucz sygnalizujący
rzeczywiste koszty poniesione na podstawie iloczynu ograniczenia i długości
że upłynął termin dostawy. Czyli:
costPerHourBeforeSoftStartTime
z 2,0 i- czas między faktyczną dostawą a początkiem przedziału czasu: 2,83583 godziny
Efekt:
model.shipments.deliveries.time_windows.cost_per_hour_before_soft_start_time
:
5.6716666666666669.
Wskaźniki te pozwalają na analizę kosztów, aby znaleźć kompromis
ograniczeń miękkich i miękkich, których możesz używać do ich dostrajania
które lepiej pasują do
Twoich reguł biznesowych. W tym przypadku łączny koszt wynosi
mniej niż shipment[1].penalty_cost
dla wartości 20,0. Optymalizator zidentyfikował
że dostawa jest bardziej ekonomiczna niż
bez przesyłki.