[英]Optaplanner: Drools rule not firing during solving, only after
我正在使用类似于optaplanner中护士计划示例的求解程序(将雇员分配到轮班中,雇员是计划变量,对计划实体进行轮班),不同的是轮班分为1小时间隔,并且每个员工可以进行多个轮班天。
硬约束之一是每个员工每个月只能工作一定的时间。 我目前使用以下规则对此建模,并且可以正常工作:
rule "At most 173h work per month per fulltime employee, assuming roster is only for 1 month"
when
$e: Employee(type == EmployeeType.FULLTIME)
$total : Number(intValue() > 10320)
from accumulate(
Shift(employee == $e,
$minutes : getTimeSlot().getMinutesInterval()),
sum($minutes))
then
scoreHolder.addHardConstraintMatch(kcontext, -1);
end
现在,由于预计需要计划很多轮班(1000多个),因此我认为可以通过跟踪每个员工的工作时间来加快处理速度。
为此,我给每个员工一个对象(统计信息),该对象应跟踪此信息。 该对象在Shift对象的setEmployee方法期间进行更新,如下所示:
public void setEmployee(Employee employee) {
if(this.employee != null){
this.employee.getStats().subtractWorkedMinutes(this.timeSlot);
}
this.employee = employee;
if(this.employee != null){
this.employee.getStats().addWorkedMinutes(this.timeSlot);
}
}
我还像在护士调度示例中一样实现了EmployeeChangeMove和ShiftAssignmentSwapMove,以确保每次移动都调用setEmployee()方法,因此应更改员工统计信息。 现在,我想在规则中使用这些增量计算的员工统计信息,如下所示:
rule "At most 173h work per month per fulltime employee, assuming roster is only for 1 month"
when
Employee(type == EmployeeType.FULLTIME,
getStats().getTotalMinutesWorked() > 10320)
then
scoreHolder.addHardConstraintMatch(kcontext, -1);
end
但是,我遇到的问题是,这些规则在求解过程中永远不会触发,并且求解器没有考虑这些因素来计算分数。 只有在求解器完成并且从解决方案中生成新的ScoreDirector以获得ConstraintMatchTotal对象之后,该规则才实际触发,并且确实显示为违反的规则。
我究竟做错了什么?
在求解过程中跟踪约束变量以在约束规则中使用变量的最佳方法是什么?
当OptaPlanner修改Shift.employee时,Drools得知Shift已修改(因此它可以进行增量增量得分计算)。 Drools没有被告知Employee也被修改了...
解决方案:使Employee.stats成为影子变量。
Employee应该是一个影子@PlanningEntity
,它的stats字段应该是一个@CustomShadowVariable
,其源是setEmployee Shift.employee
,其侦听器在Shift.setEmployee
执行代码,以便setEmployee可以再次成为一个简单的setter。
除非正在进行扫描,否则不要忘记在求解器配置中将Employee注册为计划实体。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.