内容概要
通过这篇文章,咱们来学习将ProblemFact、PlanningEntity连贯在一起以及负责与OptaPlanner交互的Solution类。
ProblemFact实例
一个布局问题的数据集须要被蕴含在一个类中,供求解器求解。该解决方案类同时代表了布局问题和(求解完结后)解决方案。它被注解为@PlanningSolution注解。 例如,云资源优化的例子中,解决方案类是CloudBalance类,它蕴含一个computerList列表,一个processList列表。
@PlanningSolution
@XStreamAlias("CloudBalance")
public class CloudBalance extends AbstractPersistable {
private List<CloudComputer> computerList;
private List<CloudProcess> processList;
......
}
复制代码
一个布局问题实际上是一个未解决的布局解决方案,或者换个说法,一个未初始化的解决方案。
例如,在云资源优化例子中,那个CloudBalance类有@PlanningSolution注解,然而未解决的processList类中的每个CloudProcess都还没有被调配到一个计算机(他们的computer属性为空)。这不是一个可行的解决方案,它甚至不是一个可能的解决方案,这是一个未初始化的解决方案。
Solution类
一个Solution类持有所有的ProblemFact、PlanningEntity和一个Score。增加@PlanningSolution注解。例如,一个loudBalance实例持有所有计算机、过程的列表。
@PlanningSolution
@XStreamAlias("CloudBalance")
public class CloudBalance extends AbstractPersistable {
private List<CloudComputer> computerList;
private List<CloudProcess> processList;
......
}
复制代码
求解器配置须要申明布局解决方案类:
<solver xmlns=”https://www.optaplanner.org/xsd/solver” xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
xsi:schemaLocation="https://www.optaplanner.org/xsd/solver https://www.optaplanner.org/xsd/solver/solver.xsd">
…
<solutionClass>org.optaplanner.examples.nqueens.domain.NQueens</solutionClass>
…
</solver>
复制代码
Solution中的PlanningEntity
OptaPlanner须要从Solution实例中提取PlanningEntity实例。它通过调用每一个被@PlanningEntityCollectionProperty正文的getter(或字段)来取得这些汇合。
@PlanningSolution
public class NQueens {
...
private List<Queen> queenList;
@PlanningEntityCollectionProperty
public List<Queen> getQueenList() {
return queenList;
}
}
复制代码
能够有多个@PlanningEntityCollectionProperty注解的属性。那些甚至能够返回一个具备雷同实体类类型的汇合,也能够返回一个数组。
@PlanningEntityCollectionProperty注解须要在具备@PlanningSolution注解的类中的一个属性上。它在没有该注解的父类或子类中被疏忽。
在极少数状况下,一个布局实体可能是一个属性:在其getter办法(或字段)上应用@PlanningEntityProperty来代替。如果启用,这两个注解也能够被主动发现。
Solution中的Score
一个@PlanningSolution类须要一个分数属性(或字段),须要增加@PlanningScore注解。如果分数还没有被计算,那么分数属性就是空的。分数属性的类型与你的用例的具体分数实现无关。例如,NQueens应用一个SimpleScore,CloudBalance应用的是HardSoftScore。
@PlanningSolution
public class NQueens {
...
private SimpleScore score;
@PlanningScore
public SimpleScore getScore() {
return score;
}
public void setScore(SimpleScore score) {
this.score = score;
}
}
复制代码
大多数用例都应用HardSoftScore:
@PlanningSolution
public class CloudBalance {
...
private HardSoftScore score;
@PlanningScore
public HardSoftScore getScore() {
return score;
}
public void setScore(HardSoftScore score) {
this.score = score;
}
}
复制代码
有些用例会应用其余分数类型。
Solution中的ProblemFact
对于束缚流和Drools分数计算,OptaPlanner须要从Solution实例中提取ProblemFact实例。它通过调用每一个带有@ProblemFactCollectionProperty注解的办法(或字段)来取得这些汇合。所有由这些办法返回的对象都能够被束缚流或Drools规定所应用。例如,在CloudBalance中,所有的computerList是问题事实。
@PlanningSolution
@XStreamAlias("CloudBalance")
public class CloudBalance extends AbstractPersistable {
private List<CloudComputer> computerList;
private List<CloudProcess> processList;
@XStreamConverter(HardSoftScoreXStreamConverter.class)
private HardSoftScore score;
public CloudBalance() {
}
public CloudBalance(long id, List<CloudComputer> computerList, List<CloudProcess> processList) {
super(id);
this.computerList = computerList;
this.processList = processList;
}
@ValueRangeProvider(id = "computerRange")
@ProblemFactCollectionProperty
public List<CloudComputer> getComputerList() {
return computerList;
}
public void setComputerList(List<CloudComputer> computerList) {
this.computerList = computerList;
}
@PlanningEntityCollectionProperty
public List<CloudProcess> getProcessList() {
return processList;
}
}
复制代码
所有的ProblemFact都会主动插入到Drools工作存内存,请留神在它们的属性上增加注解。
而且能够有多个@ProblemFactCollectionProperty注解的成属性。这些属性甚至能够返回具备雷同类别类型的汇合,但它们不应该两次返回雷同的实例,它也能够返回一个数组。
@ProblemFactCollectionProperty注解须要在一个有@PlanningSolution注解的类中的成员上。它在父类或没有该注解的子类上会被疏忽。
在极少数状况下,ProblemFact可能是一个对象:在其办法(或字段)上应用@ProblemFactProperty代替。
扩大ProblemFact
有些ProblemFact一开始并未在业务模型中的体现,然而这些ProblemFact数据能够简化束缚规定的编写,在提交求解之前,将这些数据计算出来作为一个ProblemFact放在Solution类内,能够是求解器更快、更简略的进行求解。
例如,在考试中,每两个至多共享一个学生的考试科目,就会创立一个的ProblemFact问题事实
TopicConflict。
@ProblemFactCollectionProperty
private List<TopicConflict> calculateTopicConflictList() {
List<TopicConflict> topicConflictList = new ArrayList<TopicConflict>();
for (Topic leftTopic : topicList) {
for (Topic rightTopic : topicList) {
if (leftTopic.getId() < rightTopic.getId()) {
int studentSize = 0;
for (Student student : leftTopic.getStudentList()) {
if (rightTopic.getStudentList().contains(student)) {
studentSize++;
}
}
if (studentSize > 0) {
topicConflictList.add(new TopicConflict(leftTopic, rightTopic, studentSize));
}
}
}
}
return topicConflictList;
}
复制代码
当分数束缚须要查看是否有两个具备独特学生的题目的考试被安顿在一起(取决于束缚:在同一时间,在一排,或在同一天),TopicConflict实例能够被用作问题事实,而不是必须联合每两个学生实例,在求解过程中去计算,这样会大大降低OptaPlanner求解的效率。
主动扫描属性
与其明确配置每个属性(或字段)注解,有些也能够由OptaPlanner主动推导进去。例如,在CloudBalance的例子中:
@PlanningSolution(autoDiscoverMemberType = AutoDiscoverMemberType.FIELD)public class CloudBalance {
// 主动发现为 @ProblemFactCollectionProperty
@ValueRangeProvider(id = "computerRange") // Not (yet) auto discovered
private List<CloudComputer> computerList;
// 主动发现为 @PlanningEntityCollectionProperty
private List<CloudProcess> processList;
// 主动发现为 @PlanningScore
private HardSoftScore score;
...
}
复制代码
AutoDiscoverMemberType反对:
NONE:没有主动发现。
FIELD:主动发现@PlanningSolution类中的所有字段。
GETTER:主动发现@PlanningSolution类上的所有getter。
主动注解是基于字段类型(或getter返回类型):
@ProblemFactProperty:当它不是一个汇合、一个数组、一个@PlanningEntity类或一个分数时。
@ProblemFactCollectionProperty:当它是一个不是@PlanningEntity类的汇合(或数组)的类型时。
@PlanningEntityProperty:当它是一个配置的@PlanningEntity类或子类时。
@PlanningEntityCollectionProperty:当它是一个类型为配置的@PlanningEntity类或子类的汇合(或数组)。
@PlanningScore:当它是一个分数或子类时。
最初
如果你感觉此文对你有一丁点帮忙,点个赞。或者能够退出我的开发交换群:1025263163互相学习,咱们会有业余的技术答疑解惑
如果你感觉这篇文章对你有点用的话,麻烦请给咱们的开源我的项目点点star: http://github.crmeb.net/u/defu 不胜感激 !
发表回复