有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

ProblemFact中带有InverseRelationShadow变量的java PlanningEntity字段未更新Optaplanner

我有一个问题事实AgentAvailability,它引用了一个阴影规划实体AgentAgent没有规划变量,只有一个反向相关阴影变量引用了规划实体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将随此移位而更新

问题在于来自AgentAvailabilityagent字段

据我所知,当Optaplanner克隆解决方案时,根据documentation,它重用问题事实的实例,并使用克隆来规划实体

由于AgentAvailability是一个事实,我假设它被重用(在调试器视图中,情况就是这样,初始问题和找到的最佳解决方案之间的实例是相同的)

来自ScheduleAgent也被正确克隆到溶液中

但是问题是AgentAvailability中的agent字段仍然是原始问题中的Agent实例

因此,在AgentAvailability实例中agentshiftSet字段仍然为空

这是在最后找到的最佳解决方案中的情况,也是在计算过程中

因此,我不能像这样使用约束

 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实体“重建”移位集。但是有没有办法从AgentAvailabilityAgent中的Agent实体“克隆”移位集,这样我就可以使用AgentAvailability的代理字段来更新shiftSet


共 (2) 个答案

  1. # 1 楼答案

    这是你的模型的问题。你不能期望AgentAvailability同时被克隆和不被克隆。如果AgentAvailability是一个问题事实,它将不会被克隆,因此agent的值将不会更改

    (旁注:也许我们应该检测一个实体是否是从一个规划事实中引用的,并快速失败?我不认为这种情况会导致麻烦之外的任何事情。)

    这个问题有几种解决方案。我建议您将Agent作为问题事实,并创建一个新实体AgentAssignment,将1-to-1映射到Agent。在这个模型中,您可以在其他事实中自由引用Agent事实实例

    这样,约束就相对容易编写了

    from(AgentAssignment.class)
        .join(AgentAvailability.class,
              Joiners.equal(
                  AgentAssignment::getAgent,
                  AgentAvailability::getAgent))
        .groupBy(
             (agentAssignment, agentAvailability) -> agentAssignment, 
             countBi())
        .filter((agentAssignment, availabilities) -> availabilities - agentAssignment.getShiftSet().size() > 0)
        ...
    
  2. # 2 楼答案

    作为替代解决方案,在AgentAvailability上添加@DeepPlanningClone注释:

    @DeepPlanningClone
    public class AgentAvailability ... { ... }
    

    但卢卡斯的答案更好