Оптапланер: перебрать переменную списка в файле правил drools - PullRequest
0 голосов
/ 04 января 2019

Я решаю проблему, аналогичную списку сотрудников. У меня есть дополнительное ограничение. Сотрудникам присваивается значение типа. Это жесткое ограничение, чтобы по крайней мере 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

Однако это правило не учитывает, что ограничение должно выполняться каждый день. У меня есть список строк даты. Как я могу перебрать их в файле drools таким же образом, как в перечислении EmployeeType?

Редактировать: Я нашел способ, но это похоже на взлом. При инициализации списка строк даты я также назначаю его статической переменной. Затем я могу использовать статическую переменную, аналогичную перечислению.

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 голосов
/ 07 января 2019

Ваш подход работает, но необходимость определять динамические конфигурации в статическом свойстве класса не звучит правильно (как вы указали).

Одним из решений было бы использование глобального в сеансе или наличие класса фактов, определяющего эту конфигурацию.


Использование глобального

Если вы решите воспользоваться этим подходом, вам нужно определить глобальный тип List<String> в своем DRL, а затем использовать его в своих правилах в сочетании с оператором 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

Надеюсь, это поможет,

...