前言:Google + SO + docu搜索似乎未提供相关信息。
域模型:
我的域模型尝试描绘一个包含机器列表的ProductionPlan。每台计算机都有一个链式作业列表,因此一个作业具有一个getNextEntry():Job方法,以创建一个作业列表。
我曾尝试通过链接的PlanningVariables解决此问题,但显然不了解chainedVariables / shadowVariables / anchorVariables的概念。据我了解,所有作业都已链接在一起,并且anchorShadowVariable指向列表的开头,因此也指向了计算机。
要实现链接,Job and Machine需要实现接口或扩展超类,因此我创建了ChainSuperClass。另外,我不知道是否必须覆盖getter / setter才能在Machine-Class中设置Annotations,我的猜测是由于Machine扩展了ChainSuperClass,所以这些Annotation仍然有效。
编辑:Kotlin的特定改进也受到赞赏。
我的代码执行的完整错误日志现在是:
Exception in thread "main" java.lang.IllegalArgumentException: The entityClass (class optaplanner.productionPlan.domain.ChainSuperClass) has a InverseRelationShadowVariable annotated property (nextEntry) which does not return a Collection with sourceVariableName (machine) which is not chained. Only a chained variable supports a singleton inverse.
ChainSuperClass:
@PlanningEntity
abstract class ChainSuperClass {
@PlanningId
open val id = Random.nextInt().toString()
@InverseRelationShadowVariable(sourceVariableName = "machine")
abstract fun getNextEntry(): Job?
abstract fun setNextEntry(job: Job)
}
工作:
@PlanningEntity
class Job(
val jobType: JobType,
val itemNumber: String,
val orderNumber: String,
val setupTime: Int,
val productionTime: Int
) : ChainSuperClass() {
@AnchorShadowVariable(sourceVariableName = "machine")
var machine: Machine? = null
private var nextEntry: Job? = null
@PlanningVariable(
valueRangeProviderRefs = ["jobList"],
graphType = PlanningVariableGraphType.CHAINED
)
override fun getNextEntry(): Job? {
return nextEntry
}
override fun setNextEntry(job: Job) {
this.nextEntry = nextEntry
}
}
机器:
class Machine(override val id: String, val jobTypes: List<JobType>) : ChainSuperClass() {
private var nextEntry: Job? = null
override fun setNextEntry(job: Job) {
this.nextEntry = job
}
override fun getNextEntry(): Job? {
return nextEntry!!
}
}
我认为使用链式变量实现的最重要的事情是:当您有一个实体时,说作业A,求解器为其变量分配一个值(作业/机器),这并不像链在从作业A开始向前构建。相反。通过为工作A的计划变量分配一个值,工作A在现有链的末尾获得连接。
[请查看documentation,以找到有关链接和有效链示例的更多详细信息。
通过了解这一点,应该很清楚,Job
的计划变量名称应类似于previousJobOrMachine
(您可能希望更简单的名称,例如previousStep
),而nextJob
属性是反函数由此得出的关系阴影变量(因此,当通过分配Job X。previousStep = Job C来将Job X连接到以Job C结尾的现有链时,则反关系会自动建立:Job C。nextJob = Job X)。
基于该信息,您的模型应看起来像这样:
@PlanningEntity
abstract class ChainSuperClass {
@PlanningId
open val id = Random.nextInt().toString()
// changed sourceVariableName to point to the planning variable
@InverseRelationShadowVariable(sourceVariableName = "previousStep")
abstract fun getNextEntry(): Job?
abstract fun setNextEntry(job: Job)
}
@PlanningEntity
class Job(
val jobType: JobType,
val itemNumber: String,
val orderNumber: String,
val setupTime: Int,
val productionTime: Int
) : ChainSuperClass() {
// changed sourceVariableName to point to the planning variable
@AnchorShadowVariable(sourceVariableName = "previousStep")
var machine: Machine? = null
// added planning variable
private var previousStep: ChainSuperClass? = null
private var nextEntry: Job? = null
@PlanningVariable(
// added machineList value range provider
valueRangeProviderRefs = ["jobList", "machineList"],
graphType = PlanningVariableGraphType.CHAINED
)
// getter for the new planning variable
fun getPreviousStep(): ChainSuperClass {
return previousStep
}
override fun getNextEntry(): Job? {
return nextEntry
}
override fun setNextEntry(job: Job) {
this.nextEntry = nextEntry
}
}
注意,在上一步中,我添加了machineList
作为previousStep
规划变量的可能值的来源,它可能是非空链末尾的Job
或代表空链的Machine
。