تحسين أساسيات محطات استلام الطلبات وتوصيلها

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

يوضّح المثال التالي سيناريو أساسي لمركبة واحدة وثلاث شحنات، وجميعها تنشأ من موقع واحد يُسمى مستودع.

الاطّلاع على مثال لطلب

      {
        "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
            }
          ]
        }
      }
    

حقول طلب تحسين المسار

كما هو موضّح في نظرة عامة، أهم خصائص طلبات تحسين المسارات هما vehicles وshipments.

بالإضافة إلى المركبة والشحنات، يتضمن الطلب الحقول التالية:

الخطوط المتعددة

يحدد كل من populatePolylines وpopulateTransitionPolylines ما إذا كان يجب أن يعرض تحسين المسار خطوطًا متعددة.

ترمّز الخدمة الخطوط المتعددة باستخدام برنامج الترميز المتعدد الخطوط JS لتطبيق "خرائط Google"، والذي يمثل بيانات ثنائية الخطوط باستخدام أحرف ASCII قابلة للطباعة. يمكنك استخدام أداة الترميز المتعدد الخطوط التفاعلية لعرض المسارات التي تم احتسابها من خلال "تحسين المسار". يساعد المثال في هذا الدليل على ضبط السمتَين populatePolylines وpopulateTransitionPolylines على "صحيح"، لكنّ أدلة أخرى ضبطتهما على "خطأ" لتقليل حجم الردّ.

راجِع تنسيق الخوارزمية المتعدّدة الأسطر المشفَّرة للحصول على وصف لتنسيق الترميز.

قيود الوقت العالمية

تم ضبط السمتَين model.globalStartTime وmodel.globalEndTime على فترة عشوائية 24 ساعة. يسهّل ذلك تفسير الطوابع الزمنية للمخرجات.

زيارة المواقع الجغرافية

يستخدم الطلب النموذجي model.shipments[].pickups[].arrivalLocation وmodel.shipments[].deliveries[].arrivalLocation فقط. تتوفّر أيضًا السمة departureLocation للحالات التي تغادر فيها المركبة من نقطة مختلفة عن مكان وصولها، مثل مجمّع مواقف سيارات بمدخل على أحد جانبَي المبنى ومخرج على جانب آخر. في هذا الدليل والدليل اللاحق، يُفترض أن تكون نقاط الوصول والمغادرة متطابقة.

يمكنك أيضًا الوصول إلى waypoint عند الوصول والمغادرة كبديل لـ latLng. تتيح حقول Waypoint استخدام أرقام تعريف الأماكن من Google كبديل لـ LatLng، ويمكنها أيضًا تحديد عناوين المركبات. يمكنك الاطّلاع على المستندات المرجعية (REST وgRPC) لمزيد من التفاصيل.

القيود في المثال

يقيّد هذا السيناريو المحسِّن بعدة طرق:

  1. يجب إكمال جميع الأنشطة بين وقت البدء والانتهاء العالميين. في هذا السيناريو، تُعد أوقات البدء والانتهاء قيدًا متساهلًا للغاية بالنظر إلى قُرب الشحنات والإطار الزمني العالمي الواسع.
  2. يجب أن تكتمل جميع عمليات الشحن. هذا هو السلوك التلقائي في حال عدم تحديد تكاليف العقوبات في shipments.
  3. تم ضبط costPerKilometer وcostPerHour على المركبة.

تتم معالجة التكاليف في معلمات نموذج التكلفة.

خصائص الاستجابة لتحسين التوجيه

الاطّلاع على ردّ على مثال الطلب

    {
      "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
        }
      }
    }
    

تتضمّن الاستجابة لتحسين المسار حقل routes من المستوى الأعلى يمثّل المسارات المقترَحة، مع مسار واحد لكل مركبة. بما أنّ مثال الطلب في هذا الدليل يحدّد مركبة واحدة فقط، يتضمّن routes رسالة ShipmentRoute واحدة.

ShipmentRoute مكانًا للإقامة

السمتان الأكثر أهمية لنوع الرسالة ShipmentRoute هما visits وtransitions.

تشير كل Visit إلى اكتمال عملية استلام الطلب أو عملية التسليم من إحدى VisitRequest الخاصة برسائل الطلب. يتم تعيين الزيارة بشكل فعال ليتم إنجازها بواسطة مركبة في مكان ووقت ما.

يمثّل كل Transition المركبة التي تتحرك من موقع جغرافي إلى آخر. يمكن أن تحدث الانتقالات بين نقطة بداية المركبة وموقع الزيارة ونقطة نهاية المركبة.

لإعادة إنشاء المسار الكامل للمركبة، يجب الجمع بين visits وtransitions في ShipmentRoute. يبدو دمج الحقول في تقدم نشاط المركبات كما يلي:

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

تزيد دائمًا ShipmentRoute بمقدار transitions عن visits، إذ يجب أن تنتقل المركبة من موقع البدء إلى أول زيارة لها في بداية المسار ومن آخر زيارة لها إلى آخر موقعها في نهاية المسار. إذا كانت المركبة تفتقر إلى موقع بداية أو نهاية، سيظل هناك transitions أكثر من visits لأنّ الموقع الجغرافي للزيارة الأولى أو الأخيرة يتم استخدامه كموقع بدء أو نهاية للمركبة على التوالي.

في هذا المثال، تحتوي زيارات الاستلام الثلاث الأولى على انتقالات بينها بدون مسافة والمدة لأن جميع عمليات الاستلام الثلاث تشترك في الموقع نفسه في الطلب.

يمكنك الاطّلاع على مستندات ShipmentRoute المرجعية (REST وgRPC) للحصول على مزيد من التفاصيل.

تحسين بسيط لترتيب النقاط

كما يوضح هذا المثال، تستنِد ميزة "تحسين المسارات" إلى الزيارات كسمات للشحنات، وليس لديها فكرة عن نقاط الطريق أو محطات التوقف ككيان مستقل. ومع ذلك، من الممكن تمثيل محطات التوقّف أو نقاط الطريق كشحنات ذات سمة VisitRequest واحدة فقط لاستلامها أو توصيلها. مع ذلك، يجب تخصيص costPerHour أو costPerKilometer للمركبة كي يتمكّن مزوّد التحسين من العثور على المسار الأمثل (بدلاً من العثور على أي مسار ممكن).