توجيه الأساطيل: تخصيص الشحنات للمركبات

يوضح هذا الدليل كيف يمكن أن يختلف عدد المركبات المقدَّمة في حل تحسين المسار وفقًا لمعلمات الطلب.

لا تعمل واجهة Route Optimization API على تحسين طلب إكمال الشحن فحسب، بل تخصّص أيضًا هذه الشحنات للمركبات من أجل تحسين التكاليف في ظلّ القيود التي تديرها.

في المثال الأول، يتطابق عدد المركبات مع عدد الشحنات، مع أن جميع المركبات تشترك في نفس التكلفة وخصائص الموقع. لكل مركبة تكلفة في ساعة التشغيل وتكلفة لكل كيلومتر يتم قطعه، ما سيساعد في تقليل الوقت والمسافة المقطوعة. قد يتوقع المرء أن يتم تخصيص شحنات متعددة من المركبات، لكن مثال الرد يوضح أقل حل من حيث التكلفة بالنظر إلى معلمات نموذج التكلفة المحددة.

الاطّلاع على مثال عن طلب يتضمّن عدّة مركبات

{
  "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"
          }
        ],
        "penaltyCost": 100.0
      },
      {
        "deliveries": [
          {
            "arrivalLocation": {
              "latitude": 37.789116,
              "longitude": -122.395080
            },
            "duration": "250s"
          }
        ],
        "pickups": [
          {
            "arrivalLocation": {
              "latitude": 37.794465,
              "longitude": -122.394839
            },
            "duration": "150s"
          }
        ],
        "penaltyCost": 5.0
      },
      {
        "deliveries": [
          {
            "arrivalLocation": {
              "latitude": 37.795242,
              "longitude": -122.399347
            },
            "duration": "250s"
          }
        ],
        "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": 50.0,
        "costPerKilometer": 10.0
      },
      {
        "endLocation": {
          "latitude": 37.794465,
          "longitude": -122.394839
        },
        "startLocation": {
          "latitude": 37.794465,
          "longitude": -122.394839
        },
        "costPerHour": 50.0,
        "costPerKilometer": 10.0
      },
      {
        "endLocation": {
          "latitude": 37.794465,
          "longitude": -122.394839
        },
        "startLocation": {
          "latitude": 37.794465,
          "longitude": -122.394839
        },
        "costPerHour": 50.0,
        "costPerKilometer": 10.0
      }
    ]
  }
}
    

الاطّلاع على ردّ على طلب يتضمّن عدّة مركبات

{
  "routes": [
    {
      "vehicleStartTime": "2023-01-14T00:00:00Z",
      "vehicleEndTime": "2023-01-14T00:28:22Z",
      "visits": [
        {
          "isPickup": true,
          "startTime": "2023-01-14T00:00:00Z",
          "detour": "0s"
        },
        {
          "shipmentIndex": 2,
          "isPickup": true,
          "startTime": "2023-01-14T00:02:30Z",
          "detour": "150s"
        },
        {
          "startTime": "2023-01-14T00:08:55Z",
          "detour": "150s"
        },
        {
          "shipmentIndex": 2,
          "startTime": "2023-01-14T00:21:21Z",
          "detour": "572s"
        }
      ],
      "transitions": [
        {
          "travelDuration": "0s",
          "waitDuration": "0s",
          "totalDuration": "0s",
          "startTime": "2023-01-14T00:00:00Z"
        },
        {
          "travelDuration": "0s",
          "waitDuration": "0s",
          "totalDuration": "0s",
          "startTime": "2023-01-14T00:02:30Z"
        },
        {
          "travelDuration": "235s",
          "travelDistanceMeters": 795,
          "waitDuration": "0s",
          "totalDuration": "235s",
          "startTime": "2023-01-14T00:05:00Z"
        },
        {
          "travelDuration": "496s",
          "travelDistanceMeters": 1893,
          "waitDuration": "0s",
          "totalDuration": "496s",
          "startTime": "2023-01-14T00:13:05Z"
        },
        {
          "travelDuration": "171s",
          "travelDistanceMeters": 665,
          "waitDuration": "0s",
          "totalDuration": "171s",
          "startTime": "2023-01-14T00:25:31Z"
        }
      ],
      "metrics": {
        "performedShipmentCount": 2,
        "travelDuration": "902s",
        "waitDuration": "0s",
        "delayDuration": "0s",
        "breakDuration": "0s",
        "visitDuration": "800s",
        "totalDuration": "1702s",
        "travelDistanceMeters": 3353
      },
      "routeCosts": {
        "model.vehicles.cost_per_kilometer": 33.53,
        "model.vehicles.cost_per_hour": 23.638888888888889
      },
      "routeTotalCost": 57.168888888888887
    },
    {
      "vehicleIndex": 1
    },
    {
      "vehicleIndex": 2
    }
  ],
  "skippedShipments": [
    {
      "index": 1
    }
  ],
  "metrics": {
    "aggregatedRouteMetrics": {
      "performedShipmentCount": 2,
      "travelDuration": "902s",
      "waitDuration": "0s",
      "delayDuration": "0s",
      "breakDuration": "0s",
      "visitDuration": "800s",
      "totalDuration": "1702s",
      "travelDistanceMeters": 3353
    },
    "usedVehicleCount": 1,
    "earliestVehicleStartTime": "2023-01-14T00:00:00Z",
    "latestVehicleEndTime": "2023-01-14T00:28:22Z",
    "totalCost": 62.168888888888887,
    "costs": {
      "model.vehicles.cost_per_hour": 23.638888888888889,
      "model.shipments.penalty_cost": 5,
      "model.vehicles.cost_per_kilometer": 33.53
    }
  }
}
    

تحدد أداة الحلّ جميع الشحنات لمركبة واحدة فقط، وتتخطّى شحنة واحدة على الرغم من توفّر الكثير من المركبات. ويرجع ذلك إلى أنّ تكلفة تشغيل مركبات إضافية مرتفعة جدًا ولا يمكن تبريرها، كما أنّ أي مركبة ليست فعّالة من حيث التكلفة لإكمال الشحنة التي تم تخطّيها نظرًا لانخفاض تكلفتها. على الرغم من سعة المركبة المتاحة، يمكن لمركبة واحدة تنفيذ جميع عمليات الشحن المحددة بأكثر الطرق فعالية من حيث التكلفة. لم يتم ضبط السمة usedIfRouteIsEmpty للمركبات في الطلب (يمكنك الاطّلاع على مستندات Vehicle (REST وgRPC) لمعرفة التفاصيل)، وبالتالي لن تتحمّل أي تكلفة في حال عدم استخدامها.

يؤدي تغيير مَعلمات التكلفة إلى منح الأولوية للحلول الأقصر على مستوى العالم بدلاً من مسارات المركبات الأقصر بشكل فردي إلى مشاركة المزيد من المركبات في الحلّ. يستبدل الطلب التالي Vehicle.costPerHour بالنموذج العالمي ShipmentModel.globalDurationCostPerHour، مع منح الأولوية للحلول الأقصر من حيث إجمالي وقت التشغيل لأي مركبة. تتم أيضًا زيادة تكلفة العقوبة المفروضة على shipment[1] لتقليل احتمالية تخطّيها.

الاطّلاع على نموذج طلب باستخدام globalDurationCostPerHour

{
  "model": {
    "globalStartTime": "2023-01-13T16:00:00-08:00",
    "globalEndTime": "2023-01-14T16:00:00-08:00",
    "globalDurationCostPerHour": 150.0,
    "shipments": [
      {
        "deliveries": [
          {
            "arrivalLocation": {
              "latitude": 37.789456,
              "longitude": -122.390192
            },
            "duration": "250s"
          }
        ],
        "pickups": [
          {
            "arrivalLocation": {
              "latitude": 37.794465,
              "longitude": -122.394839
            },
            "duration": "150s"
          }
        ],
        "penaltyCost": 100.0
      },
      {
        "deliveries": [
          {
            "arrivalLocation": {
              "latitude": 37.789116,
              "longitude": -122.395080
            },
            "duration": "250s"
          }
        ],
        "pickups": [
          {
            "arrivalLocation": {
              "latitude": 37.794465,
              "longitude": -122.394839
            },
            "duration": "150s"
          }
        ],
        "penaltyCost": 75.0
      },
      {
        "deliveries": [
          {
            "arrivalLocation": {
              "latitude": 37.795242,
              "longitude": -122.399347
            },
            "duration": "250s"
          }
        ],
        "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
        },
        "costPerKilometer": 10.0
      },
      {
        "endLocation": {
          "latitude": 37.794465,
          "longitude": -122.394839
        },
        "startLocation": {
          "latitude": 37.794465,
          "longitude": -122.394839
        },
        "costPerKilometer": 10.0
      },
      {
        "endLocation": {
          "latitude": 37.794465,
          "longitude": -122.394839
        },
        "startLocation": {
          "latitude": 37.794465,
          "longitude": -122.394839
        },
        "costPerKilometer": 10.0
      }
    ]
  }
}
    

وتوضح النتيجة أن استخدام معلمة التكلفة العالمية للتكلفة في الساعة يؤدي إلى استخدام جميع المركبات الثلاث بدلاً من استخدام سيارة واحدة فقط.

يمكنك الاطّلاع على ردّ على الطلب باستخدام globalDurationCostPerHour.

{
  "routes": [
    {
      "vehicleStartTime": "2023-01-14T00:00:00Z",
      "vehicleEndTime": "2023-01-14T00:16:20Z",
      "visits": [
        {
          "shipmentIndex": 2,
          "isPickup": true,
          "startTime": "2023-01-14T00:00:00Z",
          "detour": "0s"
        },
        {
          "shipmentIndex": 2,
          "startTime": "2023-01-14T00:09:19Z",
          "detour": "0s"
        }
      ],
      "transitions": [
        {
          "travelDuration": "0s",
          "waitDuration": "0s",
          "totalDuration": "0s",
          "startTime": "2023-01-14T00:00:00Z"
        },
        {
          "travelDuration": "409s",
          "travelDistanceMeters": 1371,
          "waitDuration": "0s",
          "totalDuration": "409s",
          "startTime": "2023-01-14T00:02:30Z"
        },
        {
          "travelDuration": "171s",
          "travelDistanceMeters": 665,
          "waitDuration": "0s",
          "totalDuration": "171s",
          "startTime": "2023-01-14T00:13:29Z"
        }
      ],
      "metrics": {
        "performedShipmentCount": 1,
        "travelDuration": "580s",
        "waitDuration": "0s",
        "delayDuration": "0s",
        "breakDuration": "0s",
        "visitDuration": "400s",
        "totalDuration": "980s",
        "travelDistanceMeters": 2036
      },
      "routeCosts": {
        "model.vehicles.cost_per_kilometer": 20.36
      },
      "routeTotalCost": 20.36
    },
    {
      "vehicleIndex": 1,
      "vehicleStartTime": "2023-01-14T00:00:00Z",
      "vehicleEndTime": "2023-01-14T00:18:54Z",
      "visits": [
        {
          "shipmentIndex": 1,
          "isPickup": true,
          "startTime": "2023-01-14T00:00:00Z",
          "detour": "0s"
        },
        {
          "shipmentIndex": 1,
          "startTime": "2023-01-14T00:08:24Z",
          "detour": "0s"
        }
      ],
      "transitions": [
        {
          "travelDuration": "0s",
          "waitDuration": "0s",
          "totalDuration": "0s",
          "startTime": "2023-01-14T00:00:00Z"
        },
        {
          "travelDuration": "354s",
          "travelDistanceMeters": 1192,
          "waitDuration": "0s",
          "totalDuration": "354s",
          "startTime": "2023-01-14T00:02:30Z"
        },
        {
          "travelDuration": "380s",
          "travelDistanceMeters": 1190,
          "waitDuration": "0s",
          "totalDuration": "380s",
          "startTime": "2023-01-14T00:12:34Z"
        }
      ],
      "metrics": {
        "performedShipmentCount": 1,
        "travelDuration": "734s",
        "waitDuration": "0s",
        "delayDuration": "0s",
        "breakDuration": "0s",
        "visitDuration": "400s",
        "totalDuration": "1134s",
        "travelDistanceMeters": 2382
      },
      "routeCosts": {
        "model.vehicles.cost_per_kilometer": 23.82
      },
      "routeTotalCost": 23.82
    },
    {
      "vehicleIndex": 2,
      "vehicleStartTime": "2023-01-14T00:00:00Z",
      "vehicleEndTime": "2023-01-14T00:16:14Z",
      "visits": [
        {
          "isPickup": true,
          "startTime": "2023-01-14T00:00:00Z",
          "detour": "0s"
        },
        {
          "startTime": "2023-01-14T00:06:25Z",
          "detour": "0s"
        }
      ],
      "transitions": [
        {
          "travelDuration": "0s",
          "waitDuration": "0s",
          "totalDuration": "0s",
          "startTime": "2023-01-14T00:00:00Z"
        },
        {
          "travelDuration": "235s",
          "travelDistanceMeters": 795,
          "waitDuration": "0s",
          "totalDuration": "235s",
          "startTime": "2023-01-14T00:02:30Z"
        },
        {
          "travelDuration": "339s",
          "travelDistanceMeters": 1276,
          "waitDuration": "0s",
          "totalDuration": "339s",
          "startTime": "2023-01-14T00:10:35Z"
        }
      ],
      "metrics": {
        "performedShipmentCount": 1,
        "travelDuration": "574s",
        "waitDuration": "0s",
        "delayDuration": "0s",
        "breakDuration": "0s",
        "visitDuration": "400s",
        "totalDuration": "974s",
        "travelDistanceMeters": 2071
      },
      "routeCosts": {
        "model.vehicles.cost_per_kilometer": 20.71
      },
      "routeTotalCost": 20.71
    }
  ],
  "metrics": {
    "aggregatedRouteMetrics": {
      "performedShipmentCount": 3,
      "travelDuration": "1888s",
      "waitDuration": "0s",
      "delayDuration": "0s",
      "breakDuration": "0s",
      "visitDuration": "1200s",
      "totalDuration": "3088s",
      "travelDistanceMeters": 6489
    },
    "usedVehicleCount": 3,
    "earliestVehicleStartTime": "2023-01-14T00:00:00Z",
    "latestVehicleEndTime": "2023-01-14T00:18:54Z",
    "totalCost": 112.14,
    "costs": {
      "model.vehicles.cost_per_kilometer": 64.89,
      "model.global_duration_cost_per_hour": 47.25
    }
  }
}
    

بناءً على ذلك، يتم استخدام جميع المركبات الثلاث (حسب metrics.usedVehicleCount) وتُسند لكل مركبة شحنة واحدة لإكمالها. عند تطابق مواقع البدء ومواقع الانتهاء وcostPerKilometer، يمكن تبديل المركبات الثلاث بشكل فعال، لذلك لا يهمّ الشحنة التي يتم إسنادها إلى أي مركبة.

تؤدي السمة globalDurationCostPerHour إلى العثور على حلّ أقصر بشكل عام، أي أنّ الفرق بين earliestVehicleStartTime وlatestVehicleEndTime لا يتجاوز 18 دقيقة و54 ثانية، مقارنةً بالمدة 28 دقيقة و22 ثانية في الردّ السابق. ومع ذلك، ارتفع مقياس "metrics.costs.model.vehicles.cost_per_kilometer"، ما يعكس المسافة الإجمالية التي قطعتها المركبات الثلاث المُستعمَلة. ويوضّح ذلك إحدى الطرق التي يتيح لك من خلالها نموذج التكلفة إجراء مقايضات:

  • زيادة في التكلفة الزمنية العالمية: يجب زيادة استخدام المركبات لتقليل الوقت الإجمالي المستغرق في إكمال النشاط التجاري، وذلك مقابل زيادة مسافة المركبة والوقت الذي تستغرقه في النقل.
  • زيادة تكلفة وقت المركبة: تقليل استخدام المركبات والوقت الذي يتم قضاؤه في نقلها على حساب حلّ شامل أطول

يُرجى العلم أنّه تم ضبط القيمة globalDurationCostPerHour التي تبلغ 150.0 في هذا المثال على ثلاثة أضعاف costPerHour للمركبات الفردية بقيمة 50.0 مقارنةً بالمثال السابق. وتتوقّع قيمة التكلفة العالمية هذه فعليًا أن تعمل المركبات الثلاث في الوقت نفسه، ولكن في أماكن عملية مثل الافتراضات، قد لا تعكس الواقع وقد يكون لها في الواقع تأثير سلبي على جودة النتائج.

كما هو موضّح في مَعلمات نماذج التكلفة، يتم التعبير عن جميع مَعلمات التكلفة بالوحدات بدون سمات نفسها، ولكن يمكن أن يكون لها معانٍ مختلفة جدًا. يجب عادةً أن ترتكز قيم مَعلمات نموذج التكلفة على أرض الواقع قدر الإمكان، لأنّ التكاليف الزائفة، مثل تلك الواردة في هذا المثال، قد تجعل واجهة برمجة التطبيقات تعمل على تحسين الأداء لتحقيق الأهداف التي لا تتطابق مع هدفك.