Как выполнить первый запрос к Route Optimization API (на примере собак)

Разработчики из Европейской экономической зоны (ЕЭЗ)

В этом документе показано, как сделать первый запрос к Route Optimization API на примере реального сценария использования.

Для простоты в примере используется HTTP и JSON, чтобы продемонстрировать REST API. Однако для рабочей среды рекомендуется использовать gRPC, поскольку он обеспечивает более высокую производительность. Однако gRPC требует установки. Подробнее о клиентских библиотеках Route Optimization API…

Сценарий

Карта Сан-Франциско с маркерами для башни Койт, парка Мишн-Долорес и парка Саут-Сансет-Плейграунд

Вы управляете службой по уходу за собаками в Сан-Франциско, которая работает с 7:00 до 19:00. Этим утром вы хотите забрать трёх собак из разных мест в городе и привезти их в свой детский сад.

Бернский зенненхунд и чихуахуа — постоянные клиенты, которые записались на прием на прошлой неделе. Немецкая овчарка – это новый запрос, поступивший в последний момент. Вы хотите принять овчарку, но не в ущерб постоянным клиентам.

У вас есть один фургон, и вы платите водителю 27 долларов в час. Водитель начинает работу в 7:00 и должен вернуться к полудню, чтобы пообедать.

Сегодня 13 февраля 2024 года. Все время в этом сценарии указано по местному времени Сан-Франциско, которое в феврале соответствует тихоокеанскому стандартному времени (UTC-8). Водитель выполняет следующие задачи:

  • Заберите бернского зенненхунда у башни Койт. Владелец запросил узкое окно вывоза между 8:00 и 8:20.
  • Заберите чихуахуа в парке South Sunset Playground. Владелец предложил более гибкое окно для самовывоза – с 7:30 до 9:30.
  • Забрать немецкую овчарку в Лэндс-Энде. Владелец также запросил узкое окно получения с 8:00 до 8:20.
  • Отвезите собак в центр передержки в парке Мишн Долорес. В детском саду требуют, чтобы детей приводили с 9:30 до 11:30.

Каждая посадка и высадка собаки занимает 5 минут.

Поскольку мыс Лэндс-Энд находится далеко от башни Койт, а временные окна для этих двух точек пересекаются, водитель не сможет забрать все три заказа. Оптимизатор должен выбрать, какую собаку пропустить, чтобы минимизировать общую стоимость (заработную плату водителя и любые штрафы за пропуск).

Подготовка

Чтобы запустить код в этом примере, сначала выполните инструкции в разделе Настройка Route Optimization API.

1. Выберите подход к оптимизации маршрутов

В Route Optimization API есть несколько методов, которые можно выбирать в зависимости от сложности задачи оптимизации.

Поскольку сценарий с передержкой собак – это небольшой и простой запрос, используйте блокирующий метод, например optimizeTours, который быстро выдает результаты для небольших запросов. Подробнее о конечных точках Route Optimization API…

Чтобы отправить HTTP-запрос POST методу optimizeTours, используйте следующий URL:

https://routeoptimization.googleapis.com/v1/projects/PROJECT_OR_ID:optimizeTours

Также необходимо задать короткие тайм-ауты и сроки, чтобы сократить время ожидания. Для нашего сценария с передержкой собак оптимизатору не нужно много времени, чтобы ответить на запрос, поэтому используйте следующие настройки:

  • Задайте для параметра timeout значение "2 секунды".
  • Оставьте настройки крайнего срока по умолчанию (60 секунд для запросов REST).

2. Как создать тело сообщения запроса

После выбора метода блокировки optimizeTours и определения настроек времени ожидания и крайнего срока следующим шагом будет создание тела сообщения запроса.

В этом сценарии запрос представляет собой сообщение OptimizeToursRequest, закодированное в формате JSON в REST API.

Чтобы создать сообщение запроса, выполните следующие действия:

  1. Начните с базовой структуры запроса, которая выглядит следующим образом:

    {
      "timeout": ...,
      "model": {
        "shipments": [...],
        "vehicles": [...],
        "globalStartTime": "...",
        "globalEndTime": "..."
      }
    }
    

    Дополнительную информацию о структуре можно найти в руководстве по ключевым концепциям Базовая структура (ShipmentModel, Shipment и Vehicle).

  2. Определите отправления. В поле shipments добавьте сообщение Shipment для каждой собаки, которую нужно забрать и вернуть утром. Здесь вы указываете предпочитаемые места и время, когда владельцы собак могут забрать своих питомцев, а также место и время, когда их можно оставить в центре.

    1. Для каждой собаки создайте один объект VisitRequest для посадки и ещё один для высадки, которая в этом сценарии называется доставкой в детский сад.

      • В пунктах посадки задайте для arrivalWaypoint место, где нужно забрать собаку (башня Койт для бернского зенненхунда, парк Саут Сансет Плейграунд для чихуахуа или Лэндс Энд для немецкой овчарки). Установите timeWindows на время, указанное владельцем (с 8:00 до 8:20 для бернского зенненхунда и немецкой овчарки и с 7:30 до 9:30 для чихуахуа).

      • В доставках задайте для arrivalWaypoint адрес детского сада, а для timeWindows – требуемое время доставки (с 9:30 до 11:30).

      • Для всех остановок задайте значение duration, равное 5 минутам (300s), чтобы учесть время на посадку и высадку собак.

      Подробнее о временных окнах…

    2. Чтобы отдать приоритет постоянным клиентам, вы задаете для атрибута penaltyCost значение 1000 для бернского зенненхунда и чихуахуа и 100 для немецкой овчарки. При установленных штрафах оптимизатор может пропустить любую из собак, но в первую очередь он рассматривает возможность пропустить немецкую овчарку (у которой штраф ниже), если ограничения делают невозможным выполнение всех погрузок.

    3. Вы можете использовать поле label, чтобы добавить идентификатор для каждой доставки, например "Бернский зенненхунд", "Чихуахуа" и "Немецкая овчарка". Это поможет вам идентифицировать отправления в ответе.

    Подробнее об определении отправлений…

  3. Определите транспортные средства. В поле vehicles добавьте сообщение Vehicle для одного фургона, указав детский сад в качестве начальной и конечной точек, стоимость оплаты труда водителя и часы работы фургона.

    1. Задайте для фургона startWaypoint и endWaypoint, соответствующие начальной и конечной точкам маршрута на день, то есть детскому саду рядом с парком Мишн-Долорес.

    2. Чтобы минимизировать операционные расходы, необходимо определить ограничения по затратам для вашего бизнеса. Задайте для параметра стоимости costPerHour значение 27 – это сумма, которую вы платите водителю за управление фургоном. Дополнительную информацию о параметрах стоимости можно найти в статье Модель стоимости.

    3. Чтобы оптимизатор создал маршрут в пределах рабочего времени фургона, определите окно работы для транспортного средства. Это окно задает ограничения по времени начала и окончания маршрута. Определив только одну половину каждого временного окна, вы дадите оптимизатору гибкость, позволяющую начать маршрут позже или закончить его раньше:

      • Если задать для параметра startTime в startTimeWindows значение 7:00, водитель сможет начать смену в 7:00 или позже, если утренних заказов нет.

      • Если в endTimeWindows для endTime задано значение "полдень", водитель должен закончить смену к полудню. Они также могут закончить свою смену, как только завершат последнюю доставку.

      Если не учитывать вторую половину окон, время ожидания и объезда для водителя будет минимальным. Подробнее о временных окнах…

    Подробнее о транспортных средствах…

  4. Задайте глобальный период времени. Глобальное временное окно – это период, в течение которого фургон может забирать и высаживать детей. В этом случае задайте для globalStartTime значение 7:00, а для globalEndTime – 19:00 13 февраля 2024 г. Это часы работы вашей гостиницы для собак.

3. Отправка запроса

Ниже приведен простой запрос curl, основанный на сценарии с передержкой собак и использующий блокирующий метод optimizeTours.

Перед отправкой запроса замените PROJECT_NUMBER_OR_ID в образце кода на идентификатор проекта Google Cloud.

curl -X POST 'https://routeoptimization.googleapis.com/v1/projects/PROJECT_NUMBER_OR_ID:optimizeTours' \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
--data @- << EOM
{
  "timeout": "2s",
  "model": {
    "shipments": [
      {
        "pickups": [
          {
            "arrivalWaypoint": {
              "location": {
                "latLng": {
                  "latitude": 37.802395,
                  "longitude": -122.405822
                }
              }
            },
            "timeWindows": [
              {
                "startTime": "2024-02-13T08:00:00-08:00",
                "endTime": "2024-02-13T08:20:00-08:00"
              }
            ],
            "duration": "300s"
          }
        ],
        "deliveries": [
          {
            "arrivalWaypoint": {
              "location": {
                "latLng": {
                  "latitude": 37.759719,
                  "longitude": -122.42798
                }
              }
            },
            "timeWindows": [
              {
                "startTime": "2024-02-13T09:30:00-08:00",
                "endTime": "2024-02-13T11:30:00-08:00"
              }
            ],
            "duration": "300s"
          }
        ],
        "label": "Bernese mountain dog",
        "penaltyCost": 1000
      },
      {
        "pickups": [
          {
            "arrivalWaypoint": {
              "location": {
                "latLng": {
                  "latitude": 37.738067,
                  "longitude": -122.498593
                }
              }
            },
            "timeWindows": [
              {
                "startTime": "2024-02-13T07:30:00-08:00",
                "endTime": "2024-02-13T09:30:00-08:00"
              }
            ],
            "duration": "300s"
          }
        ],
        "deliveries": [
          {
            "arrivalWaypoint": {
              "location": {
                "latLng": {
                  "latitude": 37.759719,
                  "longitude": -122.42798
                }
              }
            },
            "timeWindows": [
              {
                "startTime": "2024-02-13T09:30:00-08:00",
                "endTime": "2024-02-13T11:30:00-08:00"
              }
            ],
            "duration": "300s"
          }
        ],
        "label": "Chihuahua",
        "penaltyCost": 1000
      },
      {
        "pickups": [
          {
            "arrivalWaypoint": {
              "location": {
                "latLng": {
                  "latitude": 37.78018,
                  "longitude": -122.51194
                }
              }
            },
            "timeWindows": [
              {
                "startTime": "2024-02-13T08:00:00-08:00",
                "endTime": "2024-02-13T08:20:00-08:00"
              }
            ],
            "duration": "300s"
          }
        ],
        "deliveries": [
          {
            "arrivalWaypoint": {
              "location": {
                "latLng": {
                  "latitude": 37.759719,
                  "longitude": -122.42798
                }
              }
            },
            "timeWindows": [
              {
                "startTime": "2024-02-13T09:30:00-08:00",
                "endTime": "2024-02-13T11:30:00-08:00"
              }
            ],
            "duration": "300s"
          }
        ],
        "label": "German shepherd",
        "penaltyCost": 100
      }
    ],
    "vehicles": [
      {
        "startWaypoint": {
          "location": {
            "latLng": {
              "latitude": 37.759719,
              "longitude": -122.42798
            }
          }
        },
        "endWaypoint": {
          "location": {
            "latLng": {
              "latitude": 37.759719,
              "longitude": -122.42798
            }
          }
        },
        "costPerHour": 27,
        "startTimeWindows": [
          {
            "startTime": "2024-02-13T07:00:00-08:00"
          }
        ],
        "endTimeWindows": [
          {
            "endTime": "2024-02-13T12:00:00-08:00"
          }
        ]
      }
    ],
    "globalStartTime": "2024-02-13T07:00:00-08:00",
    "globalEndTime": "2024-02-13T19:00:00-08:00"
  }
}
EOM

Параметры, использованные в запросе.

В таблице ниже описаны параметры запроса, используемые в теле запроса в примере сценария. Вы можете отфильтровать содержимое по родительскому элементу или с помощью текстового поиска.

Родитель Параметр Тип ресурса Описание
OptimizeToursRequest model объект (ShipmentModel) Это основная часть вашего запроса. Это единый объект, в котором вы определяете всю задачу, включая всех собак, которых нужно забрать и высадить (shipments), и фургон в вашем автопарке (vehicles). Думайте об этом как о полном плане задачи, которую вам нужно оптимизировать.
timeout Продолжительность Этот параметр определяет максимальное время, в течение которого сервер обрабатывает запрос, прежде чем вернуть ответ. Этот параметр позволяет сократить время ожидания. Для небольших и быстрых запросов, таких как в этом сценарии с передержкой собак, установите значение 2s.
ShipmentModel shipments[] Массив объектов (Shipment) Это массив объектов, где каждый объект представляет собаку, которую нужно забрать или высадить.
vehicles[] Массив объектов (Vehicle) Это массив объектов, каждый из которых определяет транспортное средство в вашем автопарке. Здесь вы описываете свои ресурсы, например фургон, который забирает и доставляет грузы. Чтобы получить оптимизированный маршрут, необходимо определить хотя бы одно транспортное средство.
globalStartTime Временная метка Это самое раннее возможное время для любого события во всей вашей модели. Этот параметр сужает задачу оптимизации по времени, что крайне важно для точного расчета трафика и маршрутизации. В нашем сценарии с детским садом для собак укажите самое раннее время, когда водитель может начать работу, – 7:00 13 февраля 2024 года.
globalEndTime Временная метка Это самое позднее возможное время для любого события во всей модели. В нашем сценарии с детским садом для собак укажите время, когда фургон должен закончить работу, то есть 19:00 13 февраля 2024 года.
Shipment pickups[] Массив объектов (VisitRequest) Это список всех возможных вариантов самовывоза для отправления. Оптимизатор выбирает лучший вариант для решения вашей проблемы. Для этого сценария с детским садом для собак перечислите места посадки и временные интервалы, которые каждый владелец указал для каждой собаки.
deliveries[] Массив объектов (VisitRequest) Это список всех возможных вариантов доставки. Оптимизатор выбирает лучший вариант для решения вашей проблемы. Для этого сценария с передержкой собак укажите местоположение передержки и временной интервал, когда водитель должен вернуться на обед для каждой собаки.
label string Это идентификатор конкретной доставки в вашем запросе. Чтобы упростить чтение ответа, в запросе можно указать ярлыки. В нашем примере с передержкой собак используйте описательную строку, например "Чихуахуа", "Бернский зенненхунд" или кличку собаки, чтобы сопоставить решение с входными данными при получении ответа API.
penaltyCost Double Это штраф, который взимается, если оптимизатор пропускает эту отправку. По умолчанию все перевозки считаются обязательными. Оптимизатор старается минимизировать количество пропущенных обязательных перевозок и пропускает их, только если нет другого выхода. Указав штрафную стоимость, вы позволите оптимизатору пропускать отправку, если она невозможна или слишком дорога, и сможете взвешивать приоритеты между отправками. В этом случае вы устанавливаете более высокую стоимость штрафа (1000) для постоянных клиентов (бернского зенненхунда и чихуахуа) и более низкую стоимость штрафа (100) для немецкой овчарки, которую добавили в последний момент. Это указывает оптимизатору, что приоритет следует отдавать постоянным клиентам, поэтому он в первую очередь рассматривает возможность пропустить немецкую овчарку, когда не может выполнить все заказы.
VisitRequest arrivalWaypoint объект (Waypoint) Это местоположение конкретного посещения на маршруте. Его можно задать с помощью координат широты и долготы, идентификатора места или направления. В нашем примере с передержкой собак укажите в свойстве pickups адрес, предоставленный владельцем, а в свойстве deliveries – адрес центра передержки.
timeWindows[] Массив объектов (TimeWindow) Это массив объектов, которые определяют временные ограничения для самовывоза или доставки. В нашем случае это время, когда нужно забрать каждую собаку, и время, когда их нужно привезти в центр.
duration Продолжительность Этот параметр указывает продолжительность посещения (например, время погрузки или разгрузки). В этом сценарии вы устанавливаете 5-минутный буфер (300s) для всех посадок и высадок, чтобы учесть время, необходимое водителю для погрузки и выгрузки собак.
Vehicle startWaypoint объект (Waypoint) Начальная точка маршрута транспортного средства, заданная координатами широты и долготы или идентификатором места. Этот параметр сообщает оптимизатору, где транспортное средство должно начать маршрут. Если вы не укажете эту путевую точку, оптимизатор выберет в качестве начального местоположения одну из точек получения или доставки. В нашем сценарии водитель начинает день в детском саду для собак, поэтому используйте координаты парка Мишн Долорес.
endWaypoint объект (Waypoint) Конечный пункт назначения маршрута транспортного средства, заданный координатами широты и долготы или идентификатором места. Этот параметр сообщает оптимизатору, где транспортное средство должно завершить маршрут. Если вы не укажете эту путевую точку, оптимизатор выберет в качестве конца маршрута одну из точек получения или доставки. В нашем сценарии с детским садом для собак водитель должен закончить день в детском саду, поэтому используйте координаты парка Мишн Долорес.
costPerHour число Это стоимость каждого часа использования транспортного средства, независимо от того, находится ли оно в пути или остановлено. В нашем примере с детским садом для собак используйте этот параметр, чтобы смоделировать почасовую оплату водителя.
startTimeWindows[] Массив объектов (TimeWindow) Это допустимый временной интервал, в течение которого водитель может начать свою смену. В нашем примере с передержкой собак укажите в поле startTime значение "7:00", а поле endTime оставьте пустым. Это позволяет оптимизатору отложить начало смены, если первый забор груза запланирован на более позднее время. Обратите внимание, что даже если вы не укажете endTime для startTimeWindows, время начала будет неявно ограничено значением endTimeWindows. Транспортное средство должно начать маршрут до его окончания.
endTimeWindows[] Массив объектов (TimeWindow) Это допустимый временной интервал, в течение которого водитель должен завершить маршрут. В нашем примере с передержкой собак укажите endTime (полдень), но не указывайте startTime. Это позволит водителю вернуться в детский сад сразу после того, как он высадит последнего ребенка.

Далее

Интерпретация ответа