Tối ưu hoá đơn hàng dừng cơ bản cho hoạt động đến lấy hàng và giao hàng

Trường hợp này sẽ tối ưu hoá thứ tự các điểm dừng được chỉ định cho một xe bằng các tham số chi phí đơn giản. Đây là chế độ đơn giản nhất trong hoạt động Tối ưu hoá tuyến đường và đảm bảo rằng tất cả các điểm dừng đều được truy cập trong khung thời gian đã chỉ định.

Ví dụ sau minh hoạ tình huống cơ bản với một chiếc xe và 3 chuyến hàng, tất cả đều xuất phát từ một địa điểm duy nhất được gọi là kho hàng.

Xem yêu cầu mẫu

      {
        "populatePolylines": true,
        "populateTransitionPolylines": true,
        "model": {
          "globalStartTime": "2023-01-13T16:00:00-08:00",
          "globalEndTime": "2023-01-14T16:00:00-08:00",
          "shipments": [
            {
              "deliveries": [
                {
                  "arrivalLocation": {
                    "latitude": 37.789456,
                    "longitude": -122.390192
                  },
                  "duration": "250s"
                }
              ],
              "pickups": [
                {
                  "arrivalLocation": {
                    "latitude": 37.794465,
                    "longitude": -122.394839
                  },
                  "duration": "150s"
                }
              ]
            },
            {
              "deliveries": [
                {
                  "arrivalLocation": {
                    "latitude": 37.789116,
                    "longitude": -122.395080
                  },
                  "duration": "250s"
                }
              ],
              "pickups": [
                {
                  "arrivalLocation": {
                    "latitude": 37.794465,
                    "longitude": -122.394839
                  },
                  "duration": "150s"
                }
              ]
            },
            {
              "deliveries": [
                {
                  "arrivalLocation": {
                    "latitude": 37.795242,
                    "longitude": -122.399347
                  },
                  "duration": "250s"
                }
              ],
              "pickups": [
                {
                  "arrivalLocation": {
                    "latitude": 37.794465,
                    "longitude": -122.394839
                  },
                  "duration": "150s"
                }
              ]
            }
          ],
          "vehicles": [
            {
              "endLocation": {
                "latitude": 37.794465,
                "longitude": -122.394839
              },
              "startLocation": {
                "latitude": 37.794465,
                "longitude": -122.394839
              },
              "costPerKilometer": 10.0,
              "costPerHour": 40.0
            }
          ]
        }
      }
    

Trường yêu cầu Tối ưu hoá tuyến đường

Như đã đề cập trong phần Tổng quan, các thuộc tính yêu cầu Tối ưu hoá tuyến đường quan trọng nhất là vehiclesshipments.

Ngoài xe và lô hàng, yêu cầu còn bao gồm các trường sau:

Hình nhiều đường

populatePolylinespopulateTransitionPolylines chỉ định xem tính năng Tối ưu hoá tuyến đường có trả về hình nhiều đường hay không.

Dịch vụ này mã hoá nhiều đường bằng bộ mã hoá và giải mã nhiều dòng của Maps JS, đại diện cho dữ liệu nhiều đường nhị phân bằng các ký tự ASCII có thể in. Bạn có thể sử dụng Tiện ích bộ mã hoá đa tuyến tương tác để trực quan hoá các đường dẫn được tính toán bằng tính năng Tối ưu hoá tuyến đường. Ví dụ trong hướng dẫn này đặt populatePolylinespopulateTransitionPolylines thành true nhưng các hướng dẫn khác lại đặt các giá trị này thành false để giảm kích thước phản hồi.

Hãy xem nội dung Định dạng thuật toán nhiều dòng đã mã hoá để biết nội dung mô tả về định dạng mã hoá.

Giới hạn về thời gian trên toàn cục

model.globalStartTimemodel.globalEndTime được đặt trong khoảng thời gian 24 giờ tuỳ ý. Cách này giúp dấu thời gian đầu ra dễ diễn giải hơn.

Ghé thăm địa điểm

Yêu cầu mẫu chỉ sử dụng model.shipments[].pickups[].arrivalLocationmodel.shipments[].deliveries[].arrivalLocation. Ngoài ra, bạn cũng có thể dùng thuộc tính departureLocation cho các tình huống mà xe rời khỏi một điểm khác với điểm đến, chẳng hạn như khu phức hợp đỗ xe có lối vào ở một bên của toà nhà và lối ra ở một bên khác. Trong hướng dẫn này và các hướng dẫn tiếp theo, điểm đến và điểm khởi hành được giả định là giống nhau.

Thông tin về điểm đến và điểm khởi hành waypoint cũng được dùng để thay thế cho latLng. Các trường Waypoint hỗ trợ sử dụng Mã địa điểm của Google như một giải pháp thay thế cho LatLng và cũng có thể chỉ định tiêu đề xe. Hãy xem tài liệu tham khảo (REST, gRPC) để biết thêm thông tin chi tiết.

Các quy tắc ràng buộc trong ví dụ này

Trường hợp này sẽ ràng buộc trình tối ưu hoá theo một số cách:

  1. Bạn phải hoàn thành tất cả hoạt động trong khoảng thời gian từ thời điểm bắt đầu đến kết thúc trên toàn cục. Trong trường hợp này, thời gian bắt đầu và thời gian kết thúc là một ràng buộc rất lỏng lẻo do các lô hàng vận chuyển gần nhau và khoảng thời gian toàn cầu rộng.
  2. Bạn phải hoàn thành tất cả các lô hàng. Đây là hành vi mặc định khi chi phí phạt không được chỉ định trên shipments.
  3. costPerKilometercostPerHour được đặt trên xe.

Chi phí được đề cập trong Thông số mô hình chi phí.

Thuộc tính phản hồi Tối ưu hoá tuyến đường

Xem phản hồi cho yêu cầu mẫu

    {
      "routes": [
        {
          "vehicleStartTime": "2023-01-14T00:00:00Z",
          "vehicleEndTime": "2023-01-14T00:36:41Z",
          "visits": [
            {
              "shipmentIndex": 2,
              "isPickup": true,
              "startTime": "2023-01-14T00:00:00Z",
              "detour": "0s"
            },
            {
              "shipmentIndex": 1,
              "isPickup": true,
              "startTime": "2023-01-14T00:02:30Z",
              "detour": "150s"
            },
            {
              "isPickup": true,
              "startTime": "2023-01-14T00:05:00Z",
              "detour": "300s"
            },
            {
              "startTime": "2023-01-14T00:11:25Z",
              "detour": "0s"
            },
            {
              "shipmentIndex": 1,
              "startTime": "2023-01-14T00:19:29Z",
              "detour": "503s"
            },
            {
              "shipmentIndex": 2,
              "startTime": "2023-01-14T00:29:02Z",
              "detour": "1324s"
            }
          ],
          "transitions": [
            {
              "travelDuration": "0s",
              "waitDuration": "0s",
              "totalDuration": "0s",
              "startTime": "2023-01-14T00:00:00Z",
              "routePolyline": {}
            },
            {
              "travelDuration": "0s",
              "waitDuration": "0s",
              "totalDuration": "0s",
              "startTime": "2023-01-14T00:02:30Z",
              "routePolyline": {}
            },
            {
              "travelDuration": "0s",
              "waitDuration": "0s",
              "totalDuration": "0s",
              "startTime": "2023-01-14T00:05:00Z",
              "routePolyline": {}
            },
            {
              "travelDuration": "235s",
              "travelDistanceMeters": 795,
              "waitDuration": "0s",
              "totalDuration": "235s",
              "startTime": "2023-01-14T00:07:30Z",
              "routePolyline": {
                "points": "kvteFtfjVAA?C?C@C?A?C@AFMj@s@JKb@k@Zc@LSjA}ARWDGdAxAdAvAXa@@k@AsA\\c@FKp@_A\\c@Ze@fA{ALSFGd@o@rAgBB{BZc@"
              }
            },
            {
              "travelDuration": "234s",
              "travelDistanceMeters": 793,
              "waitDuration": "0s",
              "totalDuration": "234s",
              "startTime": "2023-01-14T00:15:35Z",
              "routePolyline": {
                "points": "cwseFti_jVRWj@w@x@eAHLNRHJbApAHLX\\V^?@hA~AT\\PVFFDHDFJNp@~@NRLNNTFFUZIJY^Y^g@p@[`@KP{@fAEFSXe@l@c@h@WZY\\?BELk@v@MNa@l@"
              }
            },
            {
              "travelDuration": "323s",
              "travelDistanceMeters": 1204,
              "waitDuration": "0s",
              "totalDuration": "323s",
              "startTime": "2023-01-14T00:23:39Z",
              "routePolyline": {
                "points": "cuseFhjVSTY`@Yb@GHEDIJEF]f@IJi@r@oAbBeCfDKLaApAKNQVIPKPCDQJIBIBM@iAJeALqBVC@C?A?QBYDI@C?_@Dc@FO@a@FDp@HfAHvABVDl@Dj@PpCQDiALsALAQASKwAOgBEe@COCYEa@Es@Eg@"
              }
            },
            {
              "travelDuration": "209s",
              "travelDistanceMeters": 665,
              "waitDuration": "0s",
              "totalDuration": "209s",
              "startTime": "2023-01-14T00:33:12Z",
              "routePolyline": {
                "points": "{zteFxbajV?CAYEc@AMC_@AOAK?E?CCWAOAKCe@CY?WScDEm@d@EFA\\ENCB?XEVC^E`@EhBUVCNEB?@?\\Er@IMUe@k@k@w@AAMQa@i@SWQWMQi@u@AC?A"
              }
            }
          ],
          "routePolyline": {
            "points": "kvteFtfjVAA?C?C@C?A?C@AFMj@s@JKb@k@Zc@LSjA}ARWDGdAxAdAvAXa@@k@AsA\\c@FKp@_A\\c@Ze@fA{ALSFGd@o@rAgBB{BZc@RWj@w@x@eAHLNRHJbApAHLX\\V^?@hA~AT\\PVFFDHDFJNp@~@NRLNNTFFUZIJY^Y^g@p@[@KP{@fAEFSXe@l@c@h@WZY\\?BELk@v@MNa@l@STY@Yb@GHEDIJEF]f@IJi@r@oAbBeCfDKLaApAKNQVIPKPCDQJIBIBM@iAJeALqBVC@C?A?QBYDI@C?_@Dc@FO@a@FDp@HfAHvABVDl@Dj@PpCQDiALsALAQASKwAOgBEe@COCYEa@Es@Eg@?CAYEc@AMC_@AOAK?E?CCWAOAKCe@CY?WScDEm@d@EFA\\ENCB?XEVC^E`@EhBUVCNEB?@?\\Er@IMUe@k@k@w@AAMQa@i@SWQWMQi@u@AC?A"
          },
          "metrics": {
            "performedShipmentCount": 3,
            "travelDuration": "1001s",
            "waitDuration": "0s",
            "delayDuration": "0s",
            "breakDuration": "0s",
            "visitDuration": "1200s",
            "totalDuration": "2201s",
            "travelDistanceMeters": 3457
          },
          "travelSteps": [
            {
              "duration": "0s",
              "routePolyline": {}
            },
            {
              "duration": "0s",
              "routePolyline": {}
            },
            {
              "duration": "0s",
              "routePolyline": {}
            },
            {
              "duration": "227s",
              "distanceMeters": 794,
              "routePolyline": {
                "points": "kvteFtfjVAA?C?C@C?A?C@AFMj@s@JKb@k@Zc@LSjA}ARWDGdAxAdAvAXa@@k@AsA\\c@FKp@_A\\c@Ze@fA{ALSFGd@o@rAgBB{BZc@"
              }
            },
            {
              "duration": "233s",
              "distanceMeters": 791,
              "routePolyline": {
                "points": "cwseFti_jVRWj@w@x@eAHLNRHJbApAHLX\\V^?@hA~AT\\PVFFDHDFJNp@~@NRLNNTFFUZIJY^Y^g@p@[`@KP{@fAEFSXe@l@c@h@WZY\\?BELk@v@MNa@l@"
              }
            },
            {
              "duration": "322s",
              "distanceMeters": 1205,
              "routePolyline": {
                "points": "cuseFhjVSTY`@Yb@GHEDIJEF]f@IJi@r@oAbBeCfDKLaApAKNQVIPKPCDQJIBIBM@iAJeALqBVC@C?A?QBYDI@C?_@Dc@FO@a@FDp@HfAHvABVDl@Dj@PpCQDiALsALAQASKwAOgBEe@COCYEa@Es@Eg@"
              }
            },
            {
              "duration": "208s",
              "distanceMeters": 666,
              "routePolyline": {
                "points": "{zteFxbajV?CAYEc@AMC_@AOAK?E?CCWAOAKCe@CY?WScDEm@d@EFA\\ENCB?XEVC^E`@EhBUVCNEB?@?\\Er@IMUe@k@k@w@AAMQa@i@SWQWMQi@u@AC?A"
              }
            }
          ],
          "vehicleDetour": "2201s",
          "routeCosts": {
            "model.vehicles.cost_per_hour": 24.455555555555556,
            "model.vehicles.cost_per_kilometer": 34.57
          },
          "routeTotalCost": 59.025555555555556
        }
      ],
      "totalCost": 59.025555555555556,
      "metrics": {
        "aggregatedRouteMetrics": {
          "performedShipmentCount": 3,
          "travelDuration": "1001s",
          "waitDuration": "0s",
          "delayDuration": "0s",
          "breakDuration": "0s",
          "visitDuration": "1200s",
          "totalDuration": "2201s",
          "travelDistanceMeters": 3457
        },
        "usedVehicleCount": 1,
        "earliestVehicleStartTime": "2023-01-14T00:00:00Z",
        "latestVehicleEndTime": "2023-01-14T00:36:41Z",
        "totalCost": 59.025555555555556,
        "costs": {
          "model.vehicles.cost_per_kilometer": 34.57,
          "model.vehicles.cost_per_hour": 24.455555555555556
        }
      }
    }
    

Phản hồi về tính năng Tối ưu hoá tuyến đường có trường routes cấp cao nhất đại diện cho các tuyến đường đề xuất, với một tuyến đường cho mỗi xe. Vì yêu cầu mẫu trong hướng dẫn này chỉ chỉ định một loại xe, nên routes sẽ bao gồm một thông báo ShipmentRoute.

ShipmentRoute tài sản

Hai thuộc tính quan trọng nhất cho loại thông báo ShipmentRoutevisitstransitions.

Mỗi Visit biểu thị việc hoàn tất một lượt đến lấy hàng hoặc một giao hàng từ một trong các VisitRequest của thông báo yêu cầu. Lượt ghé thăm là công việc được giao một cách hiệu quả cần được một chiếc xe hoàn thành tại một địa điểm và vào thời điểm nào đó.

Mỗi Transition đại diện cho chiếc xe đi từ vị trí này đến vị trí tiếp theo. Quá trình chuyển đổi có thể diễn ra giữa một cặp điểm bắt đầu của xe, một vị trí ghé thăm và điểm cuối của xe.

Để tạo lại tuyến đường hoàn chỉnh của xe, bạn phải kết hợp visitstransitions của ShipmentRoute. Việc kết hợp các trường vào tiến trình của hoạt động xe sẽ có dạng như sau:

request.vehicles[0].startLocation -> transitions[0] -> visits[0] ->
transitions[1] -> visits[1] -> transitions[2] -> ... -> visits[3] ->
transitions[4] -> request.vehicles[0].endLocation

ShipmentRoute luôn có nhiều hơn visits transitions, vì xe phải đi từ vị trí bắt đầu đến lượt ghé thăm đầu tiên ở đầu tuyến đường và từ lần ghé thăm cuối cùng đến vị trí kết thúc ở cuối tuyến đường. Nếu xe không có vị trí xuất phát hoặc kết thúc, thì sẽ vẫn có nhiều transitions hơn visits vì vị trí của lượt ghé thăm đầu tiên hoặc sau cùng được dùng làm vị trí xuất phát hoặc kết thúc của xe tương ứng.

Trong ví dụ này, 3 lượt đến lấy hàng đầu tiên có các lượt chuyển đổi giữa chúng với khoảng cách và thời gian bằng 0 vì cả 3 lượt đến lấy hàng đều có cùng một vị trí trong yêu cầu.

Hãy xem tài liệu tham khảo về ShipmentRoute (REST, gRPC) để biết thêm thông tin chi tiết.

Tối ưu hoá thứ tự điểm tham chiếu đơn giản

Như ví dụ này minh hoạ, các mô hình Tối ưu hoá tuyến đường truy cập dưới dạng thuộc tính của lô hàng và không có khái niệm điểm tham chiếu hoặc điểm dừng dưới dạng một thực thể độc lập. Tuy nhiên, bạn có thể biểu thị điểm dừng hoặc điểm tham chiếu là các lô hàng với chính xác một VisitRequest dưới dạng một đơn hàng đến lấy hàng hoặc giao hàng. Xe vẫn phải được chỉ định costPerHour hoặc costPerKilometer để trình tối ưu hoá tìm ra tuyến đường tối ưu (thay vì tìm mọi tuyến đường khả thi).