Как выполнить первый запрос к 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 или позже, если утренних заказов нет.

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

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

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

  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. Это позволяет водителю вернуться в детский сад сразу после того, как он высадит последнего ребенка.

Далее

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