ProblemFact中带有InverseRelationShadow变量的java PlanningEntity字段未更新Optaplanner
我有一个问题事实AgentAvailability
,它引用了一个阴影规划实体Agent
(Agent
没有规划变量,只有一个反向相关阴影变量引用了规划实体Shift
)
以下是我的类定义:
Shift.class
@PlanningEntity
public class Shift extends AbstractPersistable implements Comparable<Shift> {
@PlanningVariable(valueRangeProviderRefs = { "agentRange" }, nullable = true)
private Agent agent;
private Spot spot;
private LocalDateTime startDateTime;
private LocalDateTime endDateTime;
//Constructor, getters, setters and JPA annotations removed for clarity
Agent.class
@PlanningEntity
public class Agent implements Comparable<Agent> {
@PlanningId
private long registrationNumber;
private String username;
private boolean pro;
private SortedSet<Skill> skillSet = new TreeSet<>();
@InverseRelationShadowVariable(sourceVariableName = "agent")
private SortedSet<Shift> shiftSet = new TreeSet<>();
//Constructor, getters, setters and JPA annotations removed for clarity
AgentAvailability.class
public class AgentAvailability extends AbstractPersistable implements Comparable<AgentAvailability> {
private Agent agent;
private LocalDateTime startDateTime;
private LocalDateTime endDateTime;
//Constructor, getters, setters and JPA annotations removed for clarity
以下是我的解决方案定义:
Schedule.class
@PlanningSolution
public class Schedule extends AbstractPersistable {
// ...
@ProblemFactCollectionProperty
@ValueRangeProvider(id = "agentRange")
private List<Agent> agentList = new ArrayList<>();
@ProblemFactCollectionProperty
private List<AgentAvailability> agentAvailabilities = new ArrayList<>();
@PlanningEntityCollectionProperty
private List<Shift> shifts = new ArrayList<>();
// ...
//Constructor, getters, setters and JPA annotations removed for clarity
inverseShadowVariable正在按预期工作:当一个Agent
被分配给一个Shift
时,分配的Agent
中的shiftSet
将随此移位而更新
问题在于来自AgentAvailability
的agent
字段
据我所知,当Optaplanner克隆解决方案时,根据documentation,它重用问题事实的实例,并使用克隆来规划实体
由于AgentAvailability
是一个事实,我假设它被重用(在调试器视图中,情况就是这样,初始问题和找到的最佳解决方案之间的实例是相同的)
来自Schedule
的Agent
也被正确克隆到溶液中
但是问题是AgentAvailability
中的agent
字段仍然是原始问题中的Agent
实例
因此,在AgentAvailability
实例中agent
的shiftSet
字段仍然为空
这是在最后找到的最佳解决方案中的情况,也是在计算过程中
因此,我不能像这样使用约束:
return constraintFactory.from(AgentAvailability.class)
.groupBy(AgentAvailability::getAgent, count())
.filter((agent, availabilities) -> availabilities - agent.getShiftSet().size() > 0)
.penalizeConfigurableLong(ShiftSchedulingConstraintConfiguration.PRO_HAS_SHIFT, (agent, availabilities) -> availabilities - agent.getShiftSet().size());
因为agent.getShiftSet().size()
始终返回0,即使代理已分配给班次
一种可能的解决方法是使用from(Agent.class)子句,并与AgentAvailabilities结合,然后从Agent
实体“重建”移位集。但是有没有办法从AgentAvailability
的Agent
中的Agent
实体“克隆”移位集,这样我就可以使用AgentAvailability
的代理字段来更新shiftSet
# 1 楼答案
这是你的模型的问题。你不能期望
AgentAvailability
同时被克隆和不被克隆。如果AgentAvailability
是一个问题事实,它将不会被克隆,因此agent
的值将不会更改(旁注:也许我们应该检测一个实体是否是从一个规划事实中引用的,并快速失败?我不认为这种情况会导致麻烦之外的任何事情。)
这个问题有几种解决方案。我建议您将
Agent
作为问题事实,并创建一个新实体AgentAssignment
,将1-to-1映射到Agent
。在这个模型中,您可以在其他事实中自由引用Agent
事实实例这样,约束就相对容易编写了
# 2 楼答案
作为替代解决方案,在
AgentAvailability
上添加@DeepPlanningClone
注释:但卢卡斯的答案更好