optaplanner - 覆盖所有班次的约束
问题描述
在一个简单的排班问题中,我希望 OptaPlanner 在我的日程安排中返回“漏洞”,以便在没有具备所需技能的员工时发现某些班次。
假设 3 个基本课程,并且我只想用HardMediumSoftScore.ONE_SOFT
.
我该如何编写这样的约束?
雇员.java
public class Employee {
private long id = 0L;
private List<Skill> skills;
Shift.java
@PlanningEntity
public class Shift {
private RequiredSkills
@PlanningVariable(valueRangeProviderRefs = "employeeRange")
private Employee employee;
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ssXXX")
private OffsetDateTime start;
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ssXXX")
private OffsetDateTime end;
日程安排.java
@PlanningSolution
public class Schedule {
@PlanningEntityCollectionProperty
private List<Shift> shifts;
@ProblemFactCollectionProperty
@ValueRangeProvider(id = "employeeRange")
private List<Employee> employees;
进一步假设一个简单的ConstraintProvider
public class ScheduleConstraints implements ConstraintProvider {
@Override
public Constraint[] defineConstraints(ConstraintFactory constraintFactory) {
return new Constraint[]{
requiredSkill(constraintFactory),
};
}
private Constraint requiredSkill(ConstraintFactory constraintFactory) {
return constraintFactory.from(Shift.class)
.filter(shift -> {
return !shift.getEmployee().hasSkills(shift.getSkills());
}).penalize("Required skill", HardMediumSoftScore.ONE_HARD);
}
这是我的尝试。好吗?
private Constraint allShiftsMustBeCovered(ConstraintFactory constraintFactory) {
return constraintFactory.fromUnfiltered(Shift.class)
.filter(shift-> {
return shift.getEmployee().getId() == 0L;
}).penalize("All shifts must be covered", HardMediumSoftScore.ONE_SOFT);
}
解决方案
除非我弄错了,否则你的代码会抛出NullPointerException
s. 如果一个班次没有被覆盖,Shift.employee
是null
。您的约束假设Employee
永远不会null
- 您必须修复它,也许像这样:
// I added a null check as from() only excludes uninitialized entities.
// If employee is nullable, from() will still return Shifts with null employees.
private Constraint requiredSkill(ConstraintFactory constraintFactory) {
return constraintFactory.from(Shift.class)
.filter(shift -> shift.getEmployee() != null)
.filter(shift -> {
return !shift.getEmployee().hasSkills(shift.getSkills());
}).penalize("Required skill", HardMediumSoftScore.ONE_HARD);
}
private Constraint allShiftsMustBeCovered(ConstraintFactory constraintFactory) {
return constraintFactory.fromUnfiltered(Shift.class)
.filter(shift-> shift.getEmployee() == null ||
shift.getEmployee().getId() == 0L
).penalize("All shifts must be covered", HardMediumSoftScore.ONE_SOFT);
}
作为null
此处的有效值,请确保该Shift.employee
变量为 nullable。这种方法在文档中被称为过度约束规划。
推荐阅读
- php - 如何在 laravel 中对 2 个关系使用查询
- angular - 在 Ionic 中生成 OpenLayers 地图作为组件
- reactjs - 在 create-react-app 中运行“npm test”时如何忽略某些文件?
- batch-file - 在批处理脚本中解析特定文件夹中的大量 .xml 文件时丢弃一组特定的 .xml 文件
- java - 在测试中提供数据源 bean - 带有限定符
- ios - 在转换时间获得 - 值时,是否可以更正代码?
- c# - C# HttpClient POST 请求句柄响应
- excel - 表格和自动计算的问题
- amazon-web-services - 如何允许第 3 方通过 API 网关将对象放入 S3?
- python - 如何使用 Pandas 从数据库和本地数据框中进行选择?