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



我正在OptaPlanner中实现一个类似于NurseRoster的算法。我需要在drowls中实现一个规则,检查Employee的工作天数是否不能超过其contract的工作天数。由于我不知道如何在drowls中实现这一点,我决定将其作为一个类中的方法编写,然后在droolls中使用它来检查约束是否已被破坏。由于我需要Employee类中ShiftAssignmentsList,所以我需要使用@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

如何修复此错误?

这肯定与创建"新的最佳解决方案"时进行的解决方案克隆有关。

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

这只是我对规划实体类的一个演示:

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

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

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

最新更新