简体   繁体   English

Optaplanner:流口水的规则是:解题期间不触发

[英]Optaplanner: Drools rule not firing during solving, only after

I am working on a solver similar to the nurse scheduling example from optaplanner (Employees are assigned to shifts, employees are the planning variable, shifts the planning entity), except shifts are split into 1 hour intervals and an employee can work on multiple shifts per day. 我正在使用类似于optaplanner中护士计划示例的求解程序(将雇员分配到轮班中,雇员是计划变量,对计划实体进行轮班),不同的是轮班分为1小时间隔,并且每个员工可以进行多个轮班天。

One of the hard constraints is that each employee can only work a set amount of hours per month. 硬约束之一是每个员工每个月只能工作一定的时间。 I currently use the following rule to model this and it works: 我目前使用以下规则对此建模,并且可以正常工作:

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

Now, since it is expected that there are a lot of shifts that need to be planned (1000+) I figured I could speed up the processing by keeping track of hours worked per employee. 现在,由于预计需要计划很多轮班(1000多个),因此我认为可以通过跟踪每个员工的工作时间来加快处理速度。

To that end I give each employee an object (stats) that should track this information. 为此,我给每个员工一个对象(统计信息),该对象应跟踪此信息。 The object is updated during the Shift object's setEmployee Method like so: 该对象在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);
    }
}

I also implemented the EmployeeChangeMove and ShiftAssignmentSwapMove like in the nurse scheduling example, to make sure that each move calls the setEmployee() method and should therefore change the employee statistics. 我还像在护士调度示例中一样实现了EmployeeChangeMove和ShiftAssignmentSwapMove,以确保每次移动都调用setEmployee()方法,因此应更改员工统计信息。 Now I wanted to use these incrementally calculated employee statistics in the rules, like so: 现在,我想在规则中使用这些增量计算的员工统计信息,如下所示:

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

However, I encounter the problem that these rules are never fired during solving and aren't taking into account by the solver to calculate the scores. 但是,我遇到的问题是,这些规则在求解过程中永远不会触发,并且求解器没有考虑这些因素来计算分数。 Only after the solver is finished and I generate a new ScoreDirector from the solution to get the ConstraintMatchTotal Object is the rule actually fired and does show up as a violated rule. 只有在求解器完成并且从解决方案中生成新的ScoreDirector以获得ConstraintMatchTotal对象之后,该规则才实际触发,并且确实显示为违反的规则。

What am I doing wrong? 我究竟做错了什么?

What would be the best way to keep track of changing variables during solving to make use of them in the constraint rules? 在求解过程中跟踪约束变量以在约束规则中使用变量的最佳方法是什么?

When Shift.employee gets modified by OptaPlanner, Drools get's told that Shift is modified (so it can do delta incremental score calculation). 当OptaPlanner修改Shift.employee时,Drools得知Shift已修改(因此它可以进行增量增量得分计算)。 Drools doesn't get told that Employee is also modified... Drools没有被告知Employee也被修改了...

Solution: make that Employee.stats a shadow variable. 解决方案:使Employee.stats成为影子变量。

Employee should be a shadow @PlanningEntity and it's stats field should a @CustomShadowVariable with its source being the setEmployee Shift.employee and its listener doing the code in Shift.setEmployee so that setEmployee can become a simple setter again. Employee应该是一个影子@PlanningEntity ,它的stats字段应该是一个@CustomShadowVariable ,其源是setEmployee Shift.employee ,其侦听器在Shift.setEmployee执行代码,以便setEmployee可以再次成为一个简单的setter。

Don't forget to register Employee as a planning entity in the solver configuration unless it's doing scanning. 除非正在进行扫描,否则不要忘记在求解器配置中将Employee注册为计划实体。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM