В этом примере показано, как использовать атрибуты перехода, чтобы отдавать приоритет маршрутам, на которых забор и доставка грузов поблизости выполняются одним и тем же транспортным средством в один временной блок. Подробнее о моделировании бизнес-логики с помощью атрибутов перехода…
В этом примере:
- Доставка отправлений A, B и C осуществляется близко друг к другу на одной дороге.
- Дополнительные доставки находятся дальше по дороге.
- Для доставок не указаны сроки.
- Независимо от графика посещений, транспортное средство должно проехать по этой дороге дважды: один раз утром по пути из депо и один раз вечером на обратном пути.
- Общее расстояние и продолжительность маршрута всегда одинаковы, независимо от того, когда выполняются A, B и C.

В этой ситуации и для запроса, в котором используется только цена за час и цена за километр, оптимизированный маршрут может предусматривать обработку A и B утром и C вечером, а стоимость решения будет такой же, как если бы все три обрабатывались одновременно.
Стоимость за километр с пороговым значением
Чтобы сгруппировать посещения, сначала нужно выбрать пороговое расстояние. Это максимальное расстояние между двумя посещениями, которые вы считаете близкими. В этом примере используется пороговое значение 100 метров, что примерно соответствует одному кварталу в городской местности. Вы можете увеличить или уменьшить пороговое значение в соответствии с потребностями вашего бизнеса и предпочтениями водителей.
Чтобы сгруппировать посещения в пределах 100 метров друг от друга, вы устанавливаете высокую стоимость для первых 100 метров каждого перехода и более низкую стоимость для любых дополнительных метров перехода. Поскольку первые 100 метров – самые дорогие, оптимизатор экономит больше всего, используя переходы короче 100 метров, даже если это увеличивает общую длину маршрута.
Чтобы настроить стоимость, добавьте в ShipmentModel.transition_attributes новую запись со следующими свойствами:
- Чтобы сопоставить все возможные переходы, выберите тег, который не используется в модели, например
UNUSED_TAG. Задайте для этого тега значенияTransitionAttributes.excluded_src_tagиTransitionAttributes.excluded_dst_tag. - Настройте
TransitionAttributes.distance_limit, указав пороговое расстояние и стоимость:- Задайте для
DistanceLimit.soft_max_metersвыбранное пороговое значение. - Задайте для атрибута
DistanceLimit.cost_per_kilometer_below_soft_maxстоимость за километр ниже порогового значения. - Задайте для параметра
DistanceLimit.cost_per_kilometer_above_soft_maxзначение, равное стоимости за километр сверх порогового значения.
- Задайте для
{
"model": {
"transitionAttributes": [
{
"excluded_dst_tag": "UNUSED_TAG",
"excluded_src_tag": "UNUSED_TAG",
"distanceLimit": {
"softMaxMeters": 100,
"costPerKilometerBelowSoftMax": 50,
"costPerKilometerAboveSoftMax": 1,
}
}
]
}
}
Тег #unused_tag# не должен использоваться ни в одной отправке или транспортном средстве, чтобы соответствовать всем возможным переходам. Подробнее о том, как сопоставить все запросы на посещение…
Как работает высокая стоимость ниже порогового значения
В этом разделе показано, как стоимость ниже и выше порогового значения влияет на общую стоимость различных решений в примере сценария.
Решение 1. Выполнить задачи A и B по пути туда, а задачу C – по пути обратно.
В этом решении поставки разделены на два прохода по этой дороге. Два из них будут показаны при первом обходе, а оставшееся – при втором. Всего есть пять переходов:
| Переходы | Расстояние | Ниже порогового значения | Выше порогового значения | ||
|---|---|---|---|---|---|
| Расстояние | Стоимость | Расстояние | Стоимость | ||
| depot →A | 1000 м | 100 м | 5 | 900 м | 0,9 |
| A→B | 50 м | 50 м | 2.5 | 0 м | 0 |
| B→other | 1030 м | 100 м | 5 | 930 м | 0,93 |
| other→C | 1000 м | 100 м | 5 | 900 м | 0,9 |
| C→depot | 1080 м | 100 м | 5 | 980 м | 0,98 |
| Всего | 450 м | 22,5 | 3710 м | 3,71 | |
Общая стоимость рассчитывается как сумма двух стоимостей за километр:
- стоимость за километр ниже порогового значения (50), умноженная на общее пройденное расстояние ниже порогового значения (450 м = 0,45 км);
- стоимость за километр сверх порогового значения (1), умноженная на общее пройденное расстояние сверх порогового значения (3710 м = 3,71 км).
Общая стоимость составит 0,45 * 50 + 3,71 * 1 = 22,5 + 3,71 = 26,21.
Решение 2. Выполнить действия A, B и C по пути туда, а на обратном пути ничего не делать.
В этом решении, в отличие от решения 1, все три отправления доставляются "как группа" за один проход по дороге. В другом случае транспортное средство не останавливается вообще. Опять же, есть 5 переходов, но их длина и композиции разные:
| Переходы | Расстояние | Ниже порогового значения | Выше порогового значения | ||
|---|---|---|---|---|---|
| Расстояние | Стоимость | Расстояние | Стоимость | ||
| depot →A | 1000 м | 100 м | 5 | 900 м | 0,9 |
| A→B | 50 м | 50 м | 2.5 | 0 м | 0 |
| B→C | 30 м | 30 м | 1,5 | 0 м | 0 |
| C→другое | 1000 м | 100 м | 5 | 900 м | 0,9 |
| other→depot | 2080 м | 100 м | 5 | 1980 м | 1,98 |
| Всего | 380 м | 19 | 3780 м | 3,78 | |
Используя те же вычисления, что и в решении 1, общая стоимость составляет 0,38 * 50 + 3,78 * 1 = 19 + 3,78 = 22,78, а выполнение всех посещений за один блок времени имеет меньшую стоимость, чем выполнение их в двух группах. Вы можете усилить этот эффект, увеличив DistanceLimit.cost_per_kilometer_below_soft_max.
Почему не работает цена за километр ниже порогового значения
Поскольку вы хотите отдавать предпочтение коротким переходам, а не длинным, у вас может возникнуть соблазн установить высокую стоимость за километр для длинных переходов и сохранить низкую стоимость за километр для коротких переходов. Но на самом деле это имеет обратный эффект: поскольку первые 100 метров перехода являются самыми дешевыми, оптимизатор использует эти "дешевые" метры с наибольшим эффектом, предпочитая переходы, которые имеют близко к 100 метрам или более.
Это можно увидеть на двух примерах решений. Если поменять местами стоимость километра до и после порогового значения, стоимость маршрута изменится:
| Высокая стоимость выше порогового значения | Высокая стоимость ниже порогового значения | |||
|---|---|---|---|---|
| Решение 1 | Решение 2 | Решение 1 | Решение 2 | |
| Количество ключевых показателей эффективности ниже порогового значения | 0,45 | 0,38 | 0,45 | 0,38 |
| Цена за километр ниже порогового значения | 30,00 | 30,00 | 50,00 | 50,00 |
| Километры выше порогового значения | 3,71 | 3,78 | 3,71 | 3,78 |
| Стоимость за километр сверх порогового значения | 50,00 | 50,00 | 30,00 | 30,00 |
| Общая стоимость | 185,95 | 189,38 | 26.21 | 22,78 |
Для каждой версии жирным шрифтом выделена меньшая из двух сумм. Как видите, если задать высокую стоимость превышения порога, общая стоимость маршрута, на котором посещения сгруппированы, будет выше. Это противоположно тому, чего вы хотели достичь.