OptaPlanner Facts 是否可以包含 Planning Entity 对象?

Can OptaPlanner Facts include Planning Entity objects?

OptaPlanner Fact 可以包含规划实体吗?我的猜测是答案是否定的,因为它违反了事实不能改变的规则。

如果确实支持,我在尝试调用 getter 方法时遇到空指针异常。

规则如下,school1 是 Parings 事实的私有变量,它包含关联的规划实体。

   when
        Run($r : runId)
        Pairings(runId1 == $r, $s1 : school1.adjustment.timeAdjustment)  ...

这是堆栈跟踪。

Exception in thread "main" Exception executing consequence for rule "maximizeLiftPairings" in org.optaplanner.examples.cloudbalancing.solver: java.lang.RuntimeException: cannot invoke getter: getSchool1 [declr.class: org.optaplanner.examples.cloudbalancing.domain.Pairings; act.class: org.optaplanner.examples.cloudbalancing.domain.Pairings] (see trace)
 at org.drools.core.runtime.rule.impl.DefaultConsequenceExceptionHandler.handleException(DefaultConsequenceExceptionHandler.java:39)
 at org.drools.core.common.DefaultAgenda.fireActivation(DefaultAgenda.java:1027)
 at org.drools.core.phreak.RuleExecutor.fire(RuleExecutor.java:128)
 at org.drools.core.phreak.RuleExecutor.evaluateNetworkAndFire(RuleExecutor.java:70)
 at org.drools.core.common.DefaultAgenda.fireNextItem(DefaultAgenda.java:935)
 at org.drools.core.common.DefaultAgenda.fireAllRules(DefaultAgenda.java:1200)
 at org.drools.core.common.AbstractWorkingMemory.fireAllRules(AbstractWorkingMemory.java:957)
 at org.drools.core.common.AbstractWorkingMemory.fireAllRules(AbstractWorkingMemory.java:931)
 at org.drools.core.impl.StatefulKnowledgeSessionImpl.fireAllRules(StatefulKnowledgeSessionImpl.java:256)
 at org.optaplanner.core.impl.score.director.drools.DroolsScoreDirector.calculateScore(DroolsScoreDirector.java:98)
 at org.optaplanner.core.impl.solver.scope.DefaultSolverScope.calculateScore(DefaultSolverScope.java:101)
 at org.optaplanner.core.impl.bestsolution.BestSolutionRecaller.solvingStarted(BestSolutionRecaller.java:58)
 at org.optaplanner.core.impl.solver.DefaultSolver.solvingStarted(DefaultSolver.java:177)
 at org.optaplanner.core.impl.solver.DefaultSolver.solve(DefaultSolver.java:154)
 at org.optaplanner.examples.cloudbalancing.app.CloudBalancingHelloWorld.main(CloudBalancingHelloWorld.java:56)
Caused by: java.lang.RuntimeException: cannot invoke getter: getSchool1 [declr.class: org.optaplanner.examples.cloudbalancing.domain.Pairings; act.class: org.optaplanner.examples.cloudbalancing.domain.Pairings] (see trace)
 at org.mvel2.optimizers.impl.refl.nodes.GetterAccessor.getValue(GetterAccessor.java:74)
 at org.mvel2.ast.ASTNode.getReducedValueAccelerated(ASTNode.java:108)
 at org.mvel2.MVELRuntime.execute(MVELRuntime.java:86)
 at org.mvel2.compiler.CompiledExpression.getDirectValue(CompiledExpression.java:123)
 at org.mvel2.compiler.CompiledExpression.getValue(CompiledExpression.java:119)
 at org.mvel2.MVEL.executeExpression(MVEL.java:954)
 at org.drools.core.base.extractors.MVELNumberClassFieldReader.getValue(MVELNumberClassFieldReader.java:102)
 at org.drools.core.rule.Declaration.getValue(Declaration.java:229)
 at org.optaplanner.examples.cloudbalancing.solver.Rule_maximizeLiftPairings143464364DefaultConsequenceInvokerGenerated.evaluate(Unknown Source)
 at org.optaplanner.examples.cloudbalancing.solver.Rule_maximizeLiftPairings143464364DefaultConsequenceInvoker.evaluate(Unknown Source)
 at org.drools.core.common.DefaultAgenda.fireActivation(DefaultAgenda.java:1016)
 ... 13 more
Caused by: java.lang.RuntimeException: unable to invoke method: org.optaplanner.examples.cloudbalancing.domain.School.getAdjustment: target of method is null
 at org.mvel2.optimizers.impl.refl.nodes.GetterAccessor.getValue(GetterAccessor.java:66)
 at org.mvel2.optimizers.impl.refl.nodes.GetterAccessor.getValue(GetterAccessor.java:40)
 ... 23 more
Caused by: java.lang.NullPointerException
 at sun.reflect.GeneratedMethodAccessor4.invoke(Unknown Source)
 at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
 at java.lang.reflect.Method.invoke(Method.java:497)
 at org.mvel2.optimizers.impl.refl.nodes.GetterAccessor.getValue(GetterAccessor.java:40)
 ... 24 more

你的预感是对的,答案是没有

来自documentation:

In OptaPlanner all problems facts and planning entities are plain old JavaBeans (POJO's). You can load them from a database (JDBC/JPA/JDO), an XML file, a data repository or even a noSQL cloud. OptaPlanner doesn't care.

规划实体:

A planning entity is a JavaBean (POJO) that changes during solving, for example a Queen that changes to another row. A planning problem has multiple planning entities, for example for a single n queens problem, each Queen is a planning entity. But there's usually only 1 planning entity class, for example the Queen class.

@PlanningEntity
public class Queen {


private Column column;


// Planning variables: changes during planning, between score calculations.

private Row row;


// ... getters and setters

}

问题事实:

A problem fact is any JavaBean (POJO) with getters that does not change during planning. Implementing the interface Serializable is recommended (but not required). For example in n queens, the columns and rows are problem facts:

public class Column implements Serializable {


private int index;


// ... getters

}

此答案已记录在案。布鲁斯的回答本质上更好:)

可以,但在大多数情况下,不建议。有一些陷阱。有两种方式:

A) 将问题事实 class 变成影子计划实体 class。影子计划实体 class 是一个 class 只有影子计划变量(因此没有真正的计划变量)。当然,请确保在求解器配置中注册 class 并正确注释。但在这种情况下,它应该非常有效(包括计划克隆等)。

B) 破解它(不推荐!)。将其保留为问题事实 class,但自定义计划克隆器以便计划克隆(因为默认情况下它可能不会被克隆)。确保您首先清楚地了解 "planning clone" 的含义(请参阅文档)。它不是浅克隆,也不是深层克隆,它介于两者之间(逻辑取决于计划注释等)。这个 hack 很难正确实施(并且可能不是未来的证明)。