在规则中使用 CountableValueRange
Using CountableValueRange in rules
我目前正在为共享一些资源的任务构建一个调度应用程序。
每个任务可能使用一定百分比的资源。
我需要在 Drools 规则中检查的是每个共享资源未被并行任务使用超过 100%。
所以代码看起来像:
@Data
public class Resource {
@PlanningId
private Integer id;
private String label;
}
public class ResourceUsage {
@PlanningId
private Integer id;
private Resource resource;
private int usagePercent;
}
要安排的实体
@Data
@PlanningEntity
public class TaskAssignment {
@PlanningId
private Integer id;
@PlanningVariable(valueRangeProviderRefs = { "slotRange" })
private Integer timeSlot;
private int duration;
private ResourceUsage resourceUsage;
public Integer getEndingSlot() {
return timeSlot + duration;
}
}
终于有了解决方案
@Data
@PlanningSolution
public class PlanningSolution {
@PlanningId
private Integer id;
@PlanningEntityCollectionProperty
private List<TaskAssignment> tasks = new ArrayList<>();
@ValueRangeProvider(id = "slotRange")
public CountableValueRange<Integer> getSlotRange() {
return ValueRangeFactory.createIntValueRange(0, 10_000);
}
@ProblemFactCollectionProperty
private Set<Resource> resources = new TreeSet<>();
}
Setter 和 getter 不存在,因为我使用 Lombok 来避免编写它们。
过去,我对时隙使用 class 并编写一个规则来遍历时隙集合很容易,我能够按时隙检查每个资源的全局使用情况并在使用量大于 100% 时进行惩罚。
由于内存使用有问题,我决定将 TimeSlot class 变成 CountableValueRange 但现在,我不知道如何创建规则匹配范围的每个值。执行与之前相同的计算。
有没有办法或者我必须切换回我的 TimeSlot class?
编辑:
包含在一种影子规划实体中的影子变量可以解决问题吗?
我终于找到了一种编写规则的方法,可以避免在时隙上进行迭代。
这个想法是在分配开始时计算使用情况
rule "Maximum usage of a resource"
when
$r : Resource()
$p : TaskAssignment($id1 : id, $ts : timeSlot != null,
resourceUsage!.ressource==$r,
$usage : resourceUsage!.usagePercent);
accumulate(TaskAssignment(timeSlot != null, timeSlot <= $ts,
endingSlot > $ts, id != $id1,
resourceUsage!.ressource==$r,
$rate : resourceUsage!.usagePercent);
$s:sum($rate);
$s + $usage > 100)
then
scoreHolder.addHardConstraintMatch(kcontext, 100-($s + $usage));
end
我目前正在为共享一些资源的任务构建一个调度应用程序。 每个任务可能使用一定百分比的资源。
我需要在 Drools 规则中检查的是每个共享资源未被并行任务使用超过 100%。
所以代码看起来像:
@Data
public class Resource {
@PlanningId
private Integer id;
private String label;
}
public class ResourceUsage {
@PlanningId
private Integer id;
private Resource resource;
private int usagePercent;
}
要安排的实体
@Data
@PlanningEntity
public class TaskAssignment {
@PlanningId
private Integer id;
@PlanningVariable(valueRangeProviderRefs = { "slotRange" })
private Integer timeSlot;
private int duration;
private ResourceUsage resourceUsage;
public Integer getEndingSlot() {
return timeSlot + duration;
}
}
终于有了解决方案
@Data
@PlanningSolution
public class PlanningSolution {
@PlanningId
private Integer id;
@PlanningEntityCollectionProperty
private List<TaskAssignment> tasks = new ArrayList<>();
@ValueRangeProvider(id = "slotRange")
public CountableValueRange<Integer> getSlotRange() {
return ValueRangeFactory.createIntValueRange(0, 10_000);
}
@ProblemFactCollectionProperty
private Set<Resource> resources = new TreeSet<>();
}
Setter 和 getter 不存在,因为我使用 Lombok 来避免编写它们。
过去,我对时隙使用 class 并编写一个规则来遍历时隙集合很容易,我能够按时隙检查每个资源的全局使用情况并在使用量大于 100% 时进行惩罚。
由于内存使用有问题,我决定将 TimeSlot class 变成 CountableValueRange 但现在,我不知道如何创建规则匹配范围的每个值。执行与之前相同的计算。
有没有办法或者我必须切换回我的 TimeSlot class?
编辑: 包含在一种影子规划实体中的影子变量可以解决问题吗?
我终于找到了一种编写规则的方法,可以避免在时隙上进行迭代。 这个想法是在分配开始时计算使用情况
rule "Maximum usage of a resource"
when
$r : Resource()
$p : TaskAssignment($id1 : id, $ts : timeSlot != null,
resourceUsage!.ressource==$r,
$usage : resourceUsage!.usagePercent);
accumulate(TaskAssignment(timeSlot != null, timeSlot <= $ts,
endingSlot > $ts, id != $id1,
resourceUsage!.ressource==$r,
$rate : resourceUsage!.usagePercent);
$s:sum($rate);
$s + $usage > 100)
then
scoreHolder.addHardConstraintMatch(kcontext, 100-($s + $usage));
end