#java #optaplanner
Вопрос:
Я пытаюсь решить простую проблему с доказательством концепции с помощью Optaplanner, и я сталкиваюсь с несоответствием. Документация (и другие вопросы SO), по-видимому, указывает, что ConstraintFactory.from()
должны возвращаться только инициализированные объекты планирования. (как здесь)
У меня есть следующий объект планирования (только соответствующий код):
@PlanningEntity
public class Enrollment {
@PlanningId
private UUID id;
private Student student;
@PlanningVariable(valueRangeProviderRefs = "possibleLessons", nullable = true)
private Lesson lesson;
// No-arg constructor required for OptaPlanner
public Enrollment() {
}
public Enrollment(UUID id, Student student) {
this.id = id;
this.student = student;
}
public Student getStudent() {
return student;
}
public Lesson getLesson() {
return lesson;
}
}
и попытался ввести следующее ограничение:
private Constraint studentsLikePreferredSubjects(ConstraintFactory constraintFactory) {
return constraintFactory
.from(Enrollment.class)
.filter(enrollment -> enrollment.getStudent().getPreferredSubjects().contains(enrollment.getLesson().getSubject()))
.reward("Student likes subject bonus", HardSoftScore.ONE_SOFT);
}
Этот код НЕ работает, так как я получаю исключение nullpointerexception на getLesson
: Cannot invoke "Lesson.getSubject()" because the return value of "Enrollment.getLesson()" is null
Тем не менее, добавление фильтра для отфильтровывания нулевых уроков ДЕЙСТВИТЕЛЬНО работает:
private Constraint studentsLikePreferredSubjects(ConstraintFactory constraintFactory) {
return constraintFactory
.from(Enrollment.class)
.filter(enrollment -> enrollment.getLesson() != null)
.filter(enrollment -> enrollment.getStudent().getPreferredSubjects().contains(enrollment.getLesson().getSubject()))
.reward("Student likes subject bonus", HardSoftScore.ONE_SOFT);
}
Конечно, я мог бы просто использовать этот код, но я не понимаю, зачем это необходимо: я бы ожидал Enrollment
null
Lesson
, что в потоке не будет содержаться s с s, так как я использую from
(и нет fromUnfiltered
). Кто-нибудь может объяснить такое поведение?
Ответ №1:
ConstraintFactory.from()
возвращает только инициализированные объекты планирования, если nullable = true
только (по умолчанию значение nullable равно false, поэтому from()
фильтры).
В вашем коде nullable = true
(вы выполняете чрезмерно напряженное планирование), поэтому from()
возвращает все сущности.
Комментарии:
1. Такое поведение, я думаю, немного удивительно. Если мы когда-нибудь закончим ветвление 9.0, мы, возможно, захотим изменить это поведение .
2. @GeoffreyDeSmet Спасибо! Два быстрых замечания. Во-первых, вы говорите «если только nullable = true (что по умолчанию)», но не является ли значение по умолчанию false? Видишь docs.optaplanner.org/8.11.1.Final/optaplanner-javadoc/org/…
3. @GeoffreyDeSmet Также, для меня ваш ответ противоречит текущим документам, в частности, 4.3.4.2 Переменной планирования, на которой я основывал свой исходный код. Здесь говорится: «Потоки ограничений по умолчанию отфильтровывают объекты планирования с нулевой переменной планирования. Используйте fromUnfiltered (), чтобы избежать такого нежелательного поведения.» непосредственно после введения nullable = true. Это для меня подразумевает
from()
, что следует также фильтровать, когда значение null является истинным. Конечно, я считаю, что ваш ответ здесь правильный, но тогда, возможно, следует уточнить документы по этому вопросу.4. Это хорошая обратная связь. Очевидно, что документы могут улучшиться — мы рассмотрим это. (и да, я имел в виду «по умолчанию он равен нулю» — исправляю свой ответ).
5. Мы будем изучать это в issues.redhat.com/browse/PLANNER-2535 .