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
Określasz, kiedy odbiór lub dostawa mogą być realizowane w: Shipment.VisitRequest
w następujący sposób:
- 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
Ten przykład przedstawia trzy różne przesyłki, każdą z własną
okres 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ładowa odpowiedź z ograniczeniami przedziału czasu
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. Godzina rozpoczęcia to 17:35:50.
eliminuje konieczność czekania w miejscu wizyty do momentu,
rozpoczyna się okno czasowe 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 } } }
Przedziały czasu zostały uporządkowane według visits
pojazdu, tak że przesyłki z
są dostarczane 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
.
Ograniczenia okresu ograniczonego czasowo
Jak wspomnieliśmy pokrótce w sekcji Parametry modelu kosztu, przedziały czasowe można stosować jako ograniczenia miękkie. 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 podaj rozwiązanie, które narusza blokadę. Optymalizator powoduje też naliczanie kosztów w przypadku naruszenia zasad. Podajesz ten koszt jako dodatkowej usługi w danym okresie, zwykle jako koszt za godzinę co godzinę przed przedziałem czasowym lub po nim.
Przedziały czasu są zmniejszane za pomocą parametru softStartTime
lub softEndTime
zamiast
startTime
lub endTime
i zgodnie z ustawieniem
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.
Zobacz przykładowe żądanie z czasem twardym i pozostałym okna
{ "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 miękkie okna 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. Podobnie złagodzenie czasów zakończenia
inne przesyłki, których dostarczenie: shipment[2]
mogło zostać dostarczone po określonym czasie
kończy się.
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.