Optaplanner:遍历drools规则文件中的列表变量

时间:2019-01-04 18:06:18

标签: drools optaplanner

我正在解决类似于员工名册的问题。我还有其他限制。员工具有分配给他们的“类型”值。每天至少要有每种类型的至少1名员工是一个严格的约束。我将其建模如下:

rule "All employee types must be covered"
when
    $type: Constants.EmployeeType() from Constants.EmployeeType.values()       
    not Shift(employeeId != null, $employee: getEmployee(), $employee.getType() == $type.getValue())

then
    scoreHolder.addHardConstraintMatch(kcontext, -100);
end

但是,此规则并不认为每天都满足约束条件。我有一个日期字符串列表。如何以与EmployeeType枚举相同的方式在drools文件中对其进行迭代?

编辑:我想出了一种方法,但感觉像是在破解。初始化日期字符串列表时,我还将其分配给静态变量。然后,我可以使用类似于枚举的静态变量。

rule "All employee types must be covered"
when
    $type: Constants.EmployeeType() from Constants.EmployeeType.values()
    $date: String() from Constants.dateStringList;   
    not Shift(employeeId != null, $date == getDate(), $employee: getEmployee(), $employee.getType() == $type.getValue())

then
    scoreHolder.addHardConstraintMatch(kcontext, -100);
end

但是不要以为这是正确的方法。

1 个答案:

答案 0 :(得分:0)

您的方法可行,但是必须在类的静态属性中定义动态配置听起来并不正确(就像您指出的那样)。

一种解决方案是要么在会话中使用全局变量,要么使用指定此配置的事实类。


使用全局

如果您决定采用这种方法,则需要在DRL中定义类型为List<String>的全局变量,然后将其与memberOf运算符结合使用在规则中:

global List<String> dates;

rule "All employee types must be covered"
when
  $type: Constants.EmployeeType() from Constants.EmployeeType.values()  
  not Shift(
    employeeId != null, 
    date memberOf dates, 
    $employee: getEmployee(), 
    $employee.getType() == $type.getValue()
  )
then
  scoreHolder.addHardConstraintMatch(kcontext, -100);
end

建议在将任何事实Shift插入会话中之前为全局设置值:

List<String> dates = //get the List from somewhere
ksession.setGlobal("dates", dates);

使用实况类

除了全局变量,您还可以将配置建模为一个类。如果您想例如在规则内部修改配置,这将使事情变得容易。

对于这种方法,您首先需要具有一个包含List<String>的类。从理论上讲,您可以插入List<String>而不必将其包装在任何类中,但这会使内容难以阅读和维护。

public class DatesConfiguration { 

    private List<String> dates;

    //... getters + setters
}

然后,您需要实例化此类的对象并将其插入到会话中:

DatesConfiguration dc = new DatesConfiguration();
dc.setDates(...);

ksession.insert(dc);

此时,您创建的对象只是Drools的另一个事实,可以在您的规则中使用:

rule "All employee types must be covered"
when
  $type: Constants.EmployeeType() from Constants.EmployeeType.values()  
  DatesConfiguration($dates: dates)
  not Shift(
    employeeId != null, 
    date memberOf $dates, 
    $employee: getEmployee(), 
    $employee.getType() == $type.getValue()
  )
then
  scoreHolder.addHardConstraintMatch(kcontext, -100);
end

希望有帮助,