发出您的第一个 Route Optimization 请求…与狗狗有关

欧洲经济区 (EEA) 开发者

本文档通过一个实际用例场景,向您展示如何向 Route Optimization API 发出第一个请求。

为简单起见,该示例使用 HTTP 和 JSON 来演示 REST API。不过,对于生产环境,总体建议是使用 gRPC,因为它具有性能优势。不过,gRPC 需要进行一些安装。如需了解详情,请参阅 Route Optimization API 客户端库。

场景

一张旧金山地图,上面有科伊特塔、多洛雷斯公园和南日落游乐场公园的图钉

您在旧金山经营一家狗狗日托服务机构,营业时间为上午 7 点到晚上 7 点。今天早上,您想从城市中的不同地点接三只狗,并将它们带到您的日托中心。

伯恩山犬和吉娃娃是上周预约的老客户。德国牧羊犬是客户在最后一刻提出的新要求。您希望尽可能满足德国牧羊犬的需求,但不能以牺牲常规客户为代价。

您有一辆货车可用于这项工作,并且您需要向司机支付每小时 27 美元的费用。司机和货车于早上 7 点从您的日托中心出发,需要在中午之前完成上午的接送任务,以便午休。

今天是 2024 年 2 月 13 日。此场景中的所有时间均为旧金山当地时间,即 2 月份的太平洋标准时间 (UTC-8)。驱动程序具有以下任务:

  • 在科伊特塔附近接上伯恩山犬。车主要求在上午 8:00 至 8:20 之间接载,时间窗口很紧。
  • 在南日落游乐场公园接吉娃娃。店主提供了更灵活的取餐时间段,即上午 7:30 至 9:30。
  • 在 Land's End 接德国牧羊犬。该所有者还要求在上午 8:00 到 8:20 之间设置一个较短的取货时间段。
  • 把狗狗送到多洛雷斯公园的日托中心。日托中心要求在上午 9:30 到上午 11:30 之间送达。

每次接送狗狗都需要 5 分钟的时间来装载或卸载。

由于兰兹角距离科伊特塔较远,且两者的取件时间窗口存在冲突,因此司机无法完成所有三次取件。优化器必须选择跳过哪只狗,以最大限度地降低总费用(司机工资和任何跳过罚款)。

准备工作

如需运行此示例场景中的代码,您必须先完成设置 Route Optimization API 中的说明。

1. 选择路线优化方法

Route Optimization API 提供了多种方法供您选择,具体取决于优化问题的复杂程度。

由于此狗狗日托场景是一个小型且简单的请求,因此请使用阻塞方法(例如 optimizeTours),该方法可快速提供小型请求的结果。如需详细了解 Route Optimization API 端点,请参阅选择端点。

使用以下网址向 optimizeTours 方法发出 HTTP POST 请求:

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

您还需要将超时和截止时间设置得较短,以减少不必要的等待时间。对于此狗狗日托场景,优化器不需要太多时间来响应您的请求,因此请使用以下设置:

  • 将 timeout 参数设置为 2 秒。
  • 将截止时间设置保留为默认值,即 REST 请求为 60 秒。

2. 构建请求消息正文

选择阻塞 optimizeTours 方法并定义超时和截止时间设置后,下一步是构建请求消息的正文。

对于此场景,请求是在 REST API 中编码为 JSON 的 OptimizeToursRequest 消息。

如需构建请求消息,请按照以下步骤操作:

  1. 从基本请求结构开始,如下所示:

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

    如需详细了解结构,请参阅基本结构(ShipmentModel、Shipment 和 Vehicle)的关键概念指南。

  2. 定义配送。在 shipments 字段中,为每只需要在早上接送的狗狗添加一条 Shipment 消息。您可以在此处定义每位狗主人的首选接送地点和时间,以及日托中心的地点和送狗时间。

    1. 对于每只狗,创建一个 VisitRequest 用于接送,另一个用于送达(在本场景中称为日托中心送达)。

      • 在取件中,将 arrivalWaypoint 设置为狗狗的接送地点(伯恩山犬为科伊特塔,吉娃娃为南日落游乐场公园,德国牧羊犬为兰兹角)。将 timeWindows 设置为车主要求的上车时间(伯恩山犬和德国牧羊犬为上午 8 点到 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. 为确保优化工具在货车的营业时间内创建路线,请为车辆定义营业时间窗口。此时间窗口设置路线的开始和结束时间限制。通过仅定义每个时间窗口的一半,您可以让优化器灵活地稍后开始路线或提前结束路线:

      • 将 startTimeWindows 中的 startTime 设置为上午 7 点,意味着司机最早可以在上午 7 点开始轮班。如果没有清晨接送服务,他们也可以晚点开始。

      • 将 endTimeWindows 中的 endTime 设置为中午意味着司机必须在中午之前结束轮班。他们还可以在完成最后一单配送后 立即结束轮班

      省略另一半时间窗口可最大限度地减少司机的等待和绕行时间。如需详细了解时间窗口,请参阅时间窗口。

    如需详细了解如何定义车辆,请参阅车辆。

  4. 设置全局时间范围。全局时间窗口表示面包车全天可能为您的托儿所执行接送服务的时间范围。对于此场景,请将 2024 年 2 月 13 日的 globalStartTime 设置为上午 7 点,将 globalEndTime 设置为下午 7 点,这代表您的狗狗日托营业时间。

3. 发送请求

以下是一个基于狗狗日托场景的简单 curl 请求,它使用了阻塞 optimizeTours 方法。

在发送请求之前,请将示例代码中的 PROJECT_NUMBER_OR_ID 替换为您的 Google Cloud 项目 ID。

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 object (ShipmentModel) 这是请求的核心。这是一个单一对象,您可以在其中定义整个问题,包括您需要接送的所有狗狗 (shipments) 以及车队中的货车 (vehicles)。您可以将其视为需要优化的问题的完整蓝图。
timeout 时长 此参数指定服务器在返回响应之前处理请求的最长时间。使用此参数可缩短等待时间。对于小型和快速请求(例如此狗狗日托场景),请将此值设置为 2s。
ShipmentModel shipments[] 对象数组 (Shipment) 这是一个对象数组,其中每个对象都代表一只需要接送的狗狗。
vehicles[] 对象数组 (Vehicle) 这是一个对象数组,其中每个对象都定义了车队中的一辆车辆。您可以在此处描述您的资源,例如执行接送服务的货车。您必须至少定义一辆车才能获得优化路线。
globalStartTime 时间戳 这是整个模型中任何事件可能发生的最早时间。此参数可及时缩小优化问题的范围,这对于准确计算流量和路线至关重要。对于此狗狗日托场景,请将其设置为司机当天可以操作货车的最早时间,即 2024 年 2 月 13 日上午 7 点。
globalEndTime 时间戳 这是整个模型中任何事件可能发生的最晚时间。对于此狗狗日托场景,请将其设置为货车预计结束运营的时间,即 2024 年 2 月 13 日晚上 7 点。
Shipment pickups[] 对象数组 (VisitRequest) 这是配送的所有可能自提选项的列表。优化器会选择最适合解决您的问题的算法。对于此狗狗日托场景,请列出每位主人为每只狗狗提供的接送地点和时间范围。
deliveries[] 对象数组 (VisitRequest) 这是配送的所有可能送达选项的列表。优化器会选择最适合解决您的问题的算法。对于此狗狗日托场景,请列出狗狗日托设施的位置,以及司机需要返回为每只狗狗提供午餐的时间范围。
label 字符串 这是请求中特定配送的标识符。 您可以在请求中指定标签,以便更轻松地读取响应。对于此狗狗日托场景,请使用描述性字符串(例如“吉娃娃”“伯恩山犬”或狗狗的名字),以便在收到 API 响应时将解决方案与输入内容进行匹配。
penaltyCost double 这是优化器跳过此配送时产生的惩罚费用。默认情况下,运单是强制性的,优化工具会优先尽量减少跳过的强制性运单,并且仅在别无选择时才会跳过。设置惩罚费用后,如果某项配送不可行或执行成本过高,优化器可以跳过该配送,并让您权衡不同配送之间的优先级。在这种情况下,您需要为常规客户(伯恩山犬和吉娃娃)设置较高的惩罚费用 (1000),为最后一刻的德国牧羊犬请求设置较低的惩罚费用 (100)。这会告知优化工具优先考虑常规客户,因此当无法执行所有接送任务时,它会首先考虑跳过德国牧羊犬。
VisitRequest arrivalWaypoint object (Waypoint) 这是路线中特定到访的位置。您可以使用纬度和经度坐标、地点 ID 或方向角来定义此位置。在此狗狗日托场景中,将此属性设置为宠物主人为 pickups 提供的位置,以及日托中心的 deliveries 地址。
timeWindows[] 对象数组 (TimeWindow) 这是一个对象数组,用于定义取件或送件的时间限制。对于此场景,请使用此参数来定义每只狗的接送时间范围,以及将狗送到日托中心的可接受时间范围。
duration 时长 此参数用于指定到访时长(例如装载或卸载时间)。在这种情况下,您需要为所有接送和送达设置 5 分钟的缓冲时间 (300s),以便司机有时间让狗狗上下车。
Vehicle startWaypoint object (Waypoint) 这是车辆路线的起始位置,使用纬度和经度坐标或地点 ID 进行定义。此参数会告知优化器车辆必须从何处开始路线。如果您未定义此航点,优化工具会选择其中一个取件或送货地点作为起始位置。对于此狗狗日托场景,由于司机在日托中心开始一天的工作,因此请使用多洛雷斯公园的坐标。
endWaypoint object (Waypoint) 这是车辆路线的最终目的地,使用纬度和经度坐标或地点 ID 定义。此参数会告知优化器车辆必须在何处结束路线。如果您未定义此航点,优化器会选择其中一个取货点或送货点作为路线的终点。对于此狗狗日托场景,由于司机必须在日托中心结束一天的工作,因此请使用多洛雷斯公园的坐标。
costPerHour 数值 这是车辆每使用一小时所产生的费用,无论车辆是在行驶还是已停下。对于此狗狗日托场景,请使用此变量来模拟司机的时薪。
startTimeWindows[] 对象数组 (TimeWindow) 这是司机可以开始轮班的可接受时间范围。对于此狗狗日托场景,请将 startTime 定义为上午 7 点,但省略 endTime。这样,如果第一次取货时间在上午晚些时候,优化器就可以延迟班次的开始时间。请注意,即使您没有为 startTimeWindows 提供 endTime,开始时间也会隐式地受 endTimeWindows 限制。车辆必须在路线结束之前开始路线。
endTimeWindows[] 对象数组 (TimeWindow) 这是司机完成路线的可接受时间范围。 对于此狗狗日托场景,请将 endTime 定义为中午,但省略 startTime。这样,司机就可以在最后一次送达后立即返回日托中心。

下一步

解读响应