这是我参与更文挑战的第13天,活动详情查看: 更文挑战
内容概要
上一篇章里,我们已经学习了如何为每个约束编写ConstraintWeight,以及如何动态调整约束权重,这一章我们来学习如何查看一个求解结果,哪些约束匹配了,又是多少分值。
在开发过程中,查看约束分值的最简单方法是打印 explainScore()的返回值,但此方法只能看到大概的信息。
System.out.println(scoreManager.explainScore(solution));
例如,在会议安排中,这意味着Task S51打破了硬约束:Speaker required room tag:
Explanation of score (-1hard/-806soft):
Constraint match totals:
-1hard: constraint (Speaker required room tag) has 1 matches:
-1hard: justifications ([S51])
-340soft: constraint (Theme track conflict) has 32 matches:
-20soft: justifications ([S68, S66])
-20soft: justifications ([S61, S44])
...
...
Indictments (top 5 of 72):
-1hard/-22soft: justification (S51) has 12 matches:
-1hard: constraint (Speaker required room tag)
-10soft: constraint (Theme track conflict)
...
...
这些信息都是概略性的信息,如果要查看每个约束的匹配结果及分值,则可以通过
ConstraintMatch API进行查看。
在求解器外使用Solver
例如web界面,需要呈现一个解决方案的分数和约束匹配信息,请使用ScoreManager API。
ScoreManager<CloudBalance, HardSoftScore> scoreManager = ScoreManager.create(solverFactory);
ScoreExplanation<CloudBalance, HardSoftScore> scoreExplanation = scoreManager.explain(cloudBalance);
获取求解结果的总分值:
HardSoftScore score = scoreExplanation.getScore();
此外,ScoreExplanation可以通过约束性匹配总数 and/or 来查看分值。
约束匹配信息
要查看每个约束条件的得分,可以从ScoreExplanation中获得ConstraintMatchTotals。
Collection<ConstraintMatchTotal<HardSoftScore>> constraintMatchTotals = scoreExplanation.getConstraintMatchTotalMap().values();
for (ConstraintMatchTotal<HardSoftScore> constraintMatchTotal : constraintMatchTotals) {
String constraintName = constraintMatchTotal.getConstraintName();
// The score impact of that constraint
HardSoftScore totalScore = constraintMatchTotal.getScore();
for (ConstraintMatch<HardSoftScore> constraintMatch : constraintMatchTotal.getConstraintMatchSet()) {
List<Object> justificationList = constraintMatch.getJustificationList();
HardSoftScore score = constraintMatch.getScore();
...
}
}
每个ConstraintMathTotal数代表一个约束匹配信息,并占总分数的一部分。所有ConstraintMatchTotal.getScore()的总和等于总分数。
规划实体热图
需要在用户界面中显示一个热图,可以查看每个PlanningEntity所匹配到的约束Score信息,突出PlanningEntity和ProblemFact对Score的影响,可以从ScoreExplanation中获取Indictment信息:
Map<Object, Indictment<HardSoftScore>> indictmentMap = scoreExplanation.getIndictmentMap();
for (CloudProcess process : cloudBalance.getProcessList()) {
Indictment<HardSoftScore> indictment = indictmentMap.get(process);
if (indictment == null) {
continue;
}
// The score impact of that planning entity
HardSoftScore totalScore = indictment.getScore();
for (ConstraintMatch<HardSoftScore> constraintMatch : indictment.getConstraintMatchSet()) {
String constraintName = constraintMatch.getConstraintName();
HardSoftScore score = constraintMatch.getScore();
...
}
}
每个Indictment是对象所涉及的所有约束的总和。所有Indictment.getScoreTotal()的总和与总体分数不同,因为多个Indictments可以共享同一个ConstraintMatch。
测试约束
建议为每个分数约束单独写一个单元测试,以检查它是否正确。不同的分数计算类型会有不同的测试工具。更多内容请我们后续会学习到。
总结
这一篇章比较短,但是非常的关键,我们通常编写一个约束规则后,需要进行测试查看此约束是否生效,匹配的次数,分值的情况,如果没有这些我们没有办法去判断一个约束是否起到了作用,而且在需要做一个页面来支持动态调整PlanningEntity、ProblemFact,来观察最后的约束分值情况,以帮助我们来进行约束调整。后面我会单独抽出一个章节,来讲解如何使用。
结束语
至此我们已经学习了OptaPlanner绝大多数的概念,后面的篇章会围绕如何编写约束规则来进行,结合案例来学习,使大家更能掌握这一技能。
创作不易,禁止未授权的转载。如果我的文章对您有帮助,就请点赞/收藏/关注鼓励支持一下吧💕💕💕💕💕💕