Сортировка списка по времени в ограничении Optaplanner
У меня есть вариант использования, когда я хочу назначить продавца в список встреч. Теперь эти продавцы должны путешествовать из одной точки в другую, чтобы добраться до места встречи. Я использую Optaplanner, чтобы запланировать список продавцов на несколько встреч. У меня есть ограничение:
Next appointment start time should be after previous appointment's end time + travel time to reach the next appointment + Grace time
Constraint nextApptConflict(ConstraintFactory constraintFactory) {
return constraintFactory
// Select each pair of 2 different appointments ...
.forEachUniquePair(Appointment.class,
Joiners.equal((appt) -> appt.getRep().getUuid()))
//Sort the result based on appointment start time
//Check for time gap is feasible or not
// ... and penalize each pair with a hard weight.
.penalize(HardSoftScore.ONE_HARD)
.asConstraint("SalesRep conflict");
}
Идея состоит в том, чтобы сначала получить все встречи, назначенные каждому торговому представителю, а затем отсортировать результат по времени начала встречи, а затем проверить нарушения (если таковые имеются) и применить соответствующие санкции. Однако я не уверен, как мы можем сортировать встречи в классе ограничений и следует ли мне группировать встречу илиJoiners.equal((appt) -> appt.getRep().getUuid())
тоже правильно?
Изменить: я добавил код в соответствии с рекомендацией @lukas, но получаю следующую ошибку
Constraint nextApptConflict(ConstraintFactory constraintFactory) {
// A sales-rep can accommodate at most one appointment at the same time.
return constraintFactory
// Select each pair of 2 different appointments ...
.forEachUniquePair(Appointment.class,
Joiners.equal((appt) -> appt.getRep().getUuid()),
Joiners.greaterThanOrEqual((appt) -> appt.getEndTime()))
.ifNotExists(Appointment.class, Joiners.greaterThanOrEqual((appt) -> appt.getEndTime()))
.filter((appt1, appt2) -> {
int timeInSec = Utility.getTime(Utility.distance(appt1.getPosition(), appt2.getPosition()));
Timestamp minReachTime = new Timestamp(appt1.getEndTime().getTime() + (timeInSec+GRACE_TIME_SEC) * 1000);
return appt2.getStartTime().before(minReachTime);
})
// ... and penalize each pair with a hard weight.
.penalize(HardSoftScore.ONE_HARD)
.asConstraint("SalesRep conflict");
}
Я делаю что-то неправильно?
Редактировать 2:
Constraint nextApptConflict(ConstraintFactory constraintFactory) {
// A sales-rep can accommodate at most one appointment at the same time.
return constraintFactory
// Select each pair of 2 different appointments ...
.forEachUniquePair(Appointment.class,
Joiners.equal((appt) -> appt.getRep().getUuid()),
Joiners.greaterThanOrEqual((appt1) -> appt1.getStartTime(), (appt2)-> appt2.getEndTime()))
.ifNotExists(Appointment.class, Joiners.greaterThan((appt1, appt2) -> appt2.getStartTime(), (appt3) -> appt3.getEndTime()))
.filter((appt1, appt2) -> {
int timeInSec = Utility.getTime(Utility.distance(appt1.getPosition(), appt2.getPosition()));
Timestamp minReachTime = new Timestamp(appt1.getEndTime().getTime() + (timeInSec+GRACE_TIME_SEC) * 1000);
return appt2.getStartTime().before(minReachTime);
})
// ... and penalize each pair with a hard weight.
.penalize(HardSoftScore.ONE_HARD)
.asConstraint("SalesRep conflict");
}
1 ответ
Вам не нужно ничего сортировать. Вам нужно лучше указать свои уникальные пары:
- Выберите первую встречу (
forEach
). - Выберите вторую встречу, чтобы она начиналась после окончания первой (
join
с некоторымиlessThan
/greaterThan
столяры). - Убедитесь, что между ними нет третьей встречи (
ifNotExists
).
Это даст вам все пары последовательных встреч. Остается наказывать на основании разницы между окончанием первого и началом следующего.