OptaPlanner-实体从未添加到此ScoreDirector错误 [英] OptaPlanner - The entity was never added to this ScoreDirector error

查看:138
本文介绍了OptaPlanner-实体从未添加到此ScoreDirector错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在实现与OptaPlanner中的NurseRoster类似的算法.我需要在流口水中实施一条规则,以检查Employee是否不能超过其contract中的工作天数.由于我不知道如何在流口水中做到这一点,所以我决定将其作为类中的方法编写,然后在流口水中使用它来检查约束是否已被破坏.由于我在Employee类中需要ListList,因此我需要使用自动更新该列表的@InverseRelationShadowVariable,将Employee分配给了Shift.由于我的Employee现在必须是PlanningEntity,因此出现错误The entity was never added to this ScoreDirector.我相信该错误是由我的ShiftAssignment实体引起的,该实体的@ValueRangeProvideremployees,可以在该Shift中工作.我认为这是由于从未调用ScoreDirector.beforeEntityAddedScoreDirector.afterEntityAdded导致的错误.由于某些原因,当我从ShiftAssignment中删除该范围提供程序并将其放在NurseRoster@PlanningSolution上时,它起作用了.

I am implementing an algorithm similar to the NurseRoster one in OptaPlanner. I need to implement a rule in drools that check if the Employee cannot work more days than the number of days in his contract. Since i couldn't figure out how to make this in drools, i decided to write it as a method in a class, and then use it in drools to check if the constraint has been broken. Since i needed a List of ShiftAssignments in the Employee class, i needed to use an @InverseRelationShadowVariable that updated that list automatically an Employee got assigned to a Shift. Since my Employee now has to be a PlanningEntity, the error The entity was never added to this ScoreDirector appeared. I believe the error is caused by my ShiftAssignment entity, which has a @ValueRangeProvider of employees that can work in that Shift. I think this is due to the fact that ScoreDirector.beforeEntityAdded and ScoreDirector.afterEntityAdded were never called, hence the error. For some reason when i removed that range provider from ShiftAssignment and put it on NurseRoster which is the @PlanningSolution, it worked.

这是代码:

员工:

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

ShiftAssignment:

ShiftAssignment:

@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();
}

NurseRoster:

NurseRoster:

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

这是我用来更新listOfEmployeesThatCanWorkThisShift的方法:

And this is the method i use to update that 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

如何解决此错误?

推荐答案

这肯定与创建新的最佳解决方案"时发生的解决方案克隆有关.

This has definitely something to do with the solution cloning that is happening when a "new best solution" is created.

实施自定义解决方案克隆时遇到了相同的错误.在我的项目中,我有多个计划实体类,并且它们全部相互引用(单个值或列表).因此,当解决方案克隆发生时,需要更新引用,以便它们可以指向克隆的值.这是默认克隆过程可以毫无问题地进行的操作,因此使解决方案保持一致状态.它甚至可以正确地更新父计划实体中的计划实体实例列表(由OptaPlanner核心的"FieldAccessingSolutionCloner"类的"cloneCollectionsElementIfNeeded"方法覆盖).

I encountered the same error when i implemented custom solution cloning. In my project i have multiple planning entity classes and all of them have references to each other (either a single value or a List). So when solution cloning is happening the references need to be updated so they can point to the cloned values. This is something that the default cloning process is doing without a problem, and thus leaving the solution in a consistent state. It even updates the Lists of planning entity instances in the parent planning entities correctly (covered by the method "cloneCollectionsElementIfNeeded" from the class "FieldAccessingSolutionCloner" from the OptaPlanner core).

仅是演示,我对计划实体类有什么了解?

Just a demonstration what i have when it comes to the planning entity classes:

@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测试).

At first i did not update any of the references and got the error even for "ChildPlanningEntityClass". Then i have written the code that updates the references. When it comes to the planning entity instances that were coming from the class "ChildPlanningEntityClass" everything was okay at this point because they were pointing to the cloned object. What i did wrong in the "ParentPlanningEntityClass" case was that i did not create the "childPlanningEntityClassList" list from scratch with "new ArrayList();", but instead i just updated the elements of the list (using the "set" method) to point at the cloned instances of the "ChildPlanningEntityClass" class. When creating a "new ArrayList();", filling the elements to point to the cloned objects and setting the "childPlanningEntityClassList" list everything was consistent (tested with FULL_ASSERT).

因此,仅将其连接到我的问题,可能不是使用"new ArrayList();"从头开始创建列表"employeeAssignedToShiftAssignments".而元素只是从列表中添加或删除.因此,可能发生的情况(如果未从头开始创建列表)是可行的和新的最佳解决方案(克隆)都指向同一列表,并且当可行的解决方案将继续更改此列表时,它将破坏该列表.最好的解决方案.

So just connecting it to my issue maybe the list "employeeAssignedToShiftAssignments" is not created from scratch with "new ArrayList();" and elements instead just get added or removed from the list. So what could happen (if the list is not created from scratch) here is that both the working and the new best solution (the clone) will point to the same list and when the working solution would continue to change this list it would corrupt the best solution.

这篇关于OptaPlanner-实体从未添加到此ScoreDirector错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆