OptaPlanner - 实体从未添加到此 ScoreDirector 错误

OptaPlanner - The entity was never added to this ScoreDirector error

我正在 OptaPlanner 中实现一种类似于 NurseRoster 的算法。我需要在 drools 中实施一条规则,检查 Employee 的工作天数是否不能超过他的 contract 中的天数。由于我无法弄清楚如何在 drools 中进行此操作,因此我决定将其编写为 class 中的方法,然后在 drools 中使用它来检查约束是否已被打破。因为我需要 Employee ShiftAssignments 中的 List class,所以我需要使用 @InverseRelationShadowVariable 自动更新该列表 Employee 得到分配给了Shift。由于我的 Employee 现在必须是 PlanningEntity,因此出现了错误 The entity was never added to this ScoreDirector。我认为该错误是由我的 ShiftAssignment 实体引起的,它具有 employees@ValueRangeProvider 可以在 Shift 中工作。我认为这是由于 ScoreDirector.beforeEntityAddedScoreDirector.afterEntityAdded 从未被调用,因此出现错误。出于某种原因,当我从 ShiftAssignment 中删除该范围提供程序并将其放在 NurseRoster(即 @PlanningSolution 上时,它起作用了。

代码如下:

员工:

@InverseRelationShadowVariable(sourceVariableName = "employee")
public List<ShiftAssignment> getEmployeeAssignedToShiftAssignments() {
    return employeeAssignedToShiftAssignments;
}

班次分配:

@PlanningVariable(valueRangeProviderRefs = {
    "employeeRange" }, strengthComparatorClass =    EmployeeStrengthComparator.class,nullable = true)
public Employee getEmployee() {
    return employee;
}

// the value range for this planning entity
@ValueRangeProvider(id = "employeeRange")
public List<Employee> getPossibleEmployees() {
    return getShift().getEmployeesThatCanWorkThisShift();
}

护士名册:

@ValueRangeProvider(id = "employeeRange")
@PlanningEntityCollectionProperty
public List<Employee> getEmployeeList() {
    return employeeList;
}

这是我用来更新 listOfEmployeesThatCanWorkThisShift:

的方法
public static void checkIfAnEmployeeCanBelongInGivenShiftAssignmentValueRange(NurseRoster nurseRoster) {
    List<Shift> shiftList = nurseRoster.getShiftList();
    List<Employee> employeeList = nurseRoster.getEmployeeList();
    for (Shift shift : shiftList) {
        List<Employee> employeesThatCanWorkThisShift = new ArrayList<>();
        String shiftDate = shift.getShiftDate().getDateString();
        ShiftTypeDefinition shiftTypeDefinitionForShift = shift.getShiftType().getShiftTypeDefinition();
        for (Employee employee : employeeList) {
            AgentDailySettings agentDailySetting = SearchThroughSolution.findAgentDailySetting(employee, shiftDate);
            List<ShiftTypeDefinition> shiftTypeDefinitions = agentDailySetting.getShiftTypeDefinitions();
            if (shiftTypeDefinitions.contains(shiftTypeDefinitionForShift)) {
                employeesThatCanWorkThisShift.add(employee);

            }
        }
        shift.setEmployeesThatCanWorkThisShift(employeesThatCanWorkThisShift);
    }
}

我使用的规则:

rule "maxDaysInPeriod"
when
$shiftAssignment : ShiftAssignment(employee != null)
then
int differentDaysInPeriod = MethodsUsedInScoreCalculation.employeeMaxDaysPerPeriod($shiftAssignment.getEmployee());
int maxDaysInPeriod = $shiftAssignment.getEmployee().getAgentPeriodSettings().getMaxDaysInPeriod();
if(differentDaysInPeriod > maxDaysInPeriod)
{
scoreHolder.addHardConstraintMatch(kcontext, differentDaysInPeriod - maxDaysInPeriod);
}
end

我该如何解决这个错误?

这肯定与创建 "new best solution" 时发生的解决方案克隆有关。

我在实现自定义解决方案克隆时遇到了同样的错误。在我的项目中,我有多个规划实体 classes 并且它们都相互引用(单个值或列表)。因此,当发生解决方案克隆时,需要更新引用,以便它们可以指向克隆的值。这是默认克隆过程毫无问题地做的事情,因此使解决方案处于一致状态。它甚至可以正确更新父计划实体中的计划实体实例列表(由来自 OptaPlanner 核心的 class "FieldAccessingSolutionCloner" 的方法 "cloneCollectionsElementIfNeeded" 涵盖)。

只是演示一下我在规划实体方面的情况 classes:

@PlanningEntity
public class ParentPlanningEntityClass{
    List<ChildPlanningEntityClass> childPlanningEntityClassList;
}

@PlanningEntity
public class ChildPlanningEntityClass{
    ParentPlanningEntityClass parentPlanningEntityClass;
}

起初我没有更新任何参考资料,甚至 "ChildPlanningEntityClass" 也出现错误。然后我编写了更新引用的代码。对于来自 class "ChildPlanningEntityClass" 的计划实体实例,此时一切正常,因为它们指向克隆的对象。我在 "ParentPlanningEntityClass" 案例中做错的是我没有使用 "new ArrayList();" 从头开始​​创建 "childPlanningEntityClassList" 列表,而是我只是更新了列表的元素(使用 "set" 方法)指向 "ChildPlanningEntityClass" class 的克隆实例。创建 "new ArrayList();" 时,填充元素以指向克隆对象并设置 "childPlanningEntityClassList" 列表,一切都是一致的(使用 FULL_ASSERT 测试)。

所以只是将它与我​​的问题联系起来,也许列表 "employeeAssignedToShiftAssignments" 不是用 "new ArrayList();" 从头创建的,而只是从列表中添加或删除元素。所以可能会发生什么(如果列表不是从头开始创建的)这里是工作和新的最佳解决方案(克隆)将指向同一个列表,并且当工作解决方案继续更改此列表时它会破坏最佳解决方案。