我正在使用optaplanner弹簧靴启动器来解决员工排班问题。我有2个班级,员工和计划实体Shift。目前,我正在使用如下所示的约束提供程序根据员工的技能水平为他们分配轮班。
public class ConstraintProvider implements
org.optaplanner.core.api.score.stream.ConstraintProvider {
@Override
public Constraint[] defineConstraints(ConstraintFactory constraintFactory) {
return new Constraint[]{
requiredSkillLevelOfEmployeesForShifts(constraintFactory)
};
}
private Constraint requiredSkillLevelOfEmployeesForShifts(ConstraintFactory constraintFactory) {
return constraintFactory.from(Shift.class)
.groupBy(Shift::getEmployee, sum(Shift::getRequiredSkillLevel))
.filter((employee, requiredSkillLevel) -> requiredSkillLevel > employee.getSkillLevel())
.penalize("requiredSkillLevelForShifts",
HardSoftScore.ONE_HARD,
(employee, requiredSkillLevel) -> requiredSkillLevel - employee.getSkillLevel());
}
}
我通过JSON将班次和员工列表传递给控制器,控制器然后解决并返回最佳解决方案。
@RestController
@RequestMapping("/api")
public class RostersController {
@Autowired
private SolverManager<Roster, UUID> solverManager;
@PostMapping("/solve")
public Roster solve(@RequestBody Roster problem) {
UUID problemId = UUID.randomUUID();
// Submit the problem to start solving
SolverJob<Roster, UUID> solverJob = solverManager.solve(problemId, problem);
Roster solution;
try {
// Wait until the solving ends
solution = solverJob.getFinalBestSolution();
} catch (InterruptedException | ExecutionException e) {
throw new IllegalStateException("Solving failed.", e);
}
return solution;
}
}
我想添加另一个约束,在此我限制了员工一周可做的一次班次的数量,并且限制了员工一天最多只能做一个班次。是否可以通过添加其他约束来做到这一点,或者我是否需要某种config .xml文件以及drools .drl文件来添加更具体的约束?
DRL(scoreRules.drl
)和ConstraintProvider
是互斥的。您已经开始使用ConstraintProvider
来实现约束,因此我们继续坚持并添加您可能需要的任何新约束。 ConstraintProvider
是新的Constraint Streams API的一部分,该API可让您在Java中定义约束,并且易于使用ConstraintVerifier
进行测试。
[并且仅当您不使用optaplanner-spring-boot-starter
或quarkus-optaplanner
时,示例中才缺少一个片段,它告诉SolverManager
您的ConstraintProvider
实现的类名。您可以使用solverConfig.xml
进行操作。使用optaplanner-spring-boot-starter
或quarkus-optaplanner
会自动推断出此文件:
<?xml version="1.0" encoding="UTF-8"?>
<solver>
<solutionClass>com.your.domain.Roster</solutionClass>
<entityClass>com.your.domain.Shift</entityClass>
<scoreDirectorFactory>
<constraintProviderClass>com.your.domain.ConstraintProvider</constraintProviderClass>
</scoreDirectorFactory>
</solver>