我正在OptaPlanner中实现类似于NurseRoster的算法。我需要在drools中实施一项规则,检查Employee
是否无法比contract
中的天数工作更多天。由于我无法弄清楚如何在drools中进行此操作,因此我决定将其作为类中的方法编写,然后在drools中使用它来检查约束是否已被破坏。由于我在List
课程中需要ShiftAssignments
Employee
,我需要使用@InverseRelationShadowVariable
自动更新该列表,Employee
已分配给{ {1}}。由于我的Shift
现在必须是Employee
,因此出现错误PlanningEntity
。我认为该错误是由我的The entity was never added to this ScoreDirector
实体引起的,该实体的ShiftAssignment
@ValueRangeProvider
可以在employees
中使用。我认为这是因为Shift
和ScoreDirector.beforeEntityAdded
从未被调用,因此错误。出于某种原因,当我从ScoreDirector.afterEntityAdded
移除该范围提供程序并将其放在ShiftAssignment
NurseRoster
上时,它就有效了。
以下是代码:
员工:
@PlanningSolution
ShiftAssignment:
@InverseRelationShadowVariable(sourceVariableName = "employee")
public List<ShiftAssignment> getEmployeeAssignedToShiftAssignments() {
return employeeAssignedToShiftAssignments;
}
NurseRoster:
@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);
}
}
我该如何解决此错误?
答案 0 :(得分:1)
这肯定与解决方案克隆有关,当一个新的最佳解决方案&#34;被建造。
我实现自定义解决方案克隆时遇到了同样的错误。在我的项目中,我有多个计划实体类,并且它们都具有彼此的引用(单个值或列表)。因此,当解决方案克隆发生时,需要更新引用,以便它们可以指向克隆值。这是默认克隆过程没有问题的情况,因此使解决方案处于一致状态。它甚至可以正确地更新父计划实体中的计划实体实例列表(方法&#34; cloneCollectionsElementIfNeeded&#34;来自类&#34; FieldAccessingSolutionCloner&#34;来自OptaPlanner核心)。
只是展示我在规划实体类中所拥有的:
@PlanningEntity
public class ParentPlanningEntityClass{
List<ChildPlanningEntityClass> childPlanningEntityClassList;
}
@PlanningEntity
public class ChildPlanningEntityClass{
ParentPlanningEntityClass parentPlanningEntityClass;
}
首先,我没有更新任何引用,即使对于&#34; ChildPlanningEntityClass&#34;也得到了错误。然后我写了更新引用的代码。当谈到来自班级&#34; ChildPlanningEntityClass&#34;的计划实体实例时。此时一切都很好,因为他们指向克隆的对象。我在&#34; ParentPlanningEntityClass&#34;中做错了什么案例是我没有创建&#34; childPlanningEntityClassList&#34;使用&#34; new ArrayList();&#34;从头开始列表,但我刚刚更新了列表的元素(使用&#34; set&#34;方法)来指向&的克隆实例#34; ChildPlanningEntityClass&#34;类。在创建&#34; new ArrayList();&#34;时,填充元素以指向克隆对象并设置&#34; childPlanningEntityClassList&#34;列表一切都是一致的(用FULL_ASSERT测试)。
所以只需将它与我的问题联系起来就可以列出&#34; employeeAssignedToShiftAssignments&#34;不是从头开始用&#34; new ArrayList();&#34;而只是从列表中添加或删除元素。那么可能发生的事情(如果列表不是从头开始创建的)就是工作和新的最佳解决方案(克隆)将指向同一个列表,当工作解决方案将继续更改此列表时,它将破坏最佳方案。