Слюни - Как получить доступ к объекту в предложении THEN - PullRequest
0 голосов
/ 11 апреля 2020

У меня есть сценарий, когда данные на входе имеют разные столбцы для одного факта, то есть транспонированные данные, например, для

EmployeeID | EmpDept1 | EmpDept2 | EmpDept3 | EmpDept4 | EmpDept5

Теперь у меня есть таблица поиска, например,

DeptId | DeptName

Для меня, чтобы сделать поиск, один из способов состоит в том, чтобы создать 5 правил, таких как:

rule "Lookup dept-1 data"
when
    e: EmployeeData()
    d: DeptData(deptId == $e.EmpDept1)
then
    System.out.println(e.toString());
end

Проблема в том, что мне нужно создать 5 правил (а в моем случае еще много). Есть ли способ, которым я могу получить доступ к DeptData в предложении "THEN", а затем написать JAVA lookup?

Или, если есть какой-либо другой хороший способ, пожалуйста, дайте мне знать.

Спасибо!

Ответы [ 2 ]

0 голосов
/ 13 апреля 2020

Я решил эту проблему, используя команду «собирать»

rule "Lookup dept data"
when
    e: EmployeeData()
    d1: ArrayList() from collect (DeptData(deptId == $e.EmpDept1))
    d2: ArrayList() from collect (DeptData(deptId == $e.EmpDept2))
    d3: ArrayList() from collect (DeptData(deptId == $e.EmpDept3))
    d4: ArrayList() from collect (DeptData(deptId == $e.EmpDept4))
    d5: ArrayList() from collect (DeptData(deptId == $e.EmpDept5))
then
    System.out.println("Employee == " + e);
    if (d1.size() > 0) System.out.println("Department 1 == " + d1.get(0));
    if (d2.size() > 0) System.out.println("Department 1 == " + d2.get(0));
    if (d3.size() > 0) System.out.println("Department 1 == " + d3.get(0));
    if (d4.size() > 0) System.out.println("Department 1 == " + d4.get(0));
    if (d5.size() > 0) System.out.println("Department 1 == " + d5.get(0));
end

Функция «собирать» здесь гарантирует, что записи сотрудников не дублируются, а затем можно найти отдельные соответствующие отделы.

0 голосов
/ 12 апреля 2020

Таким образом, у вас есть сотрудник, в котором его отдел может быть указан в любом из пяти мест. Лучший способ выяснить это - выяснить, где находится отдел до того, как применить правила, а затем изменить объект, который вы передаете в правила. Вы не ограничены в отношении того, какие объекты вы передаете в правила, если они сериализуются нормально; если EmployeeData в настоящее время является необработанными результатами вызова базы данных или чего-то еще, преобразуйте нужные вам части в новый POJO и передайте его в правила.

Так что для вашего примера я бы сделал что-то вроде:

class Employee {
  private Integer employeeId;
  private Integer departmentId; // assuming the only thing you need out of Department is id

  public static Employee fromEmployeeData(EmployeeData data) {
    Employee employee = new Employee();
    employee.setEmployeeId(data.getEmployeeId());

    if (data.getDept1() != null) {
        employee.setDepartmentId(data.getDept1());
    } else if (...) {} // other else-if omitted for brevity

    return employee;
  }

  // getters and setters here
}

public void invokeRules(EmployeeData data) {
  KieSession kieSession = ...; 

  Employee employee = Employee.fromEmployeeData(data); 

  kieSession.insert( employee ); 
  kieSession.fireAllRules();
}

Затем вы можете написать правила, которые отключают идентификатор отдела:

rule "Employee is in department 6"
when
  Employee( departmentId == 6 )
then
  // do something
end

В качестве альтернативы, вы можете вызывать Java методы из когда пункт. Допустим, мы создаем класс с именем EmployeeUtils, в котором есть метод для определения отдела из EmployeeData:

class EmployeeUtils {

  public static Integer resolveDepartment(Employee e) {
    Integer deptId = null;

    if (e.getDept1Id() != null) {
      deptId = e.getDept1Id();
    } else if (...) {} // other else-if omitted for brevity

    return deptId;
  }
}

Затем этот метод можно вызвать с левой стороны следующим образом:

rule "Employee in department 6"
when
  $employee: Employee()
  Integer(this == 6) from EmployeeUtils.resolveDepartment($employee)
then
  // do something
end

Очевидно, вы могли бы также назвать его с правой стороны:

rule "Example"
when
  $employee: Employee()
then
  System.out.println("Employee is in department " + EmployeeUtils.resolveDepartment($employee));
end

В общем не рекомендуется звонить Java методов с левой стороны, потому что такие вызовы не могут быть оптимизированы. Когда вы выполняете фильтрацию, например Employee(department == 6), Drools может оптимизировать утверждения, чтобы ваши правила выполнялись быстрее. Но если вы вызываете метод Java, это похоже на черный ящик с движком Drools; он не имеет ни малейшего представления о том, что будет делать метод Java, поэтому он должен позволить ему оценивать как есть, а не выполнять работу, чтобы ускорить его.

Кроме того, как правило, также не рекомендуется передавать произвольные данные в набор правил. Передайте только те данные, которые вам нужны для применения правил. При конвертации из другого источника данных, например. из SQL результата запроса или преобразования из электронной таблицы, проанализируйте части этих других данных, которые вам действительно нужны, и передайте этот проанализированный входной объект в правила.

Я работал в компании, которая передала бы результат базы данных прямо в правилах. Логика c заключалась в том, что код был скомпилирован, поэтому, если вам нужно внести изменения в объект ввода правил, вам нужно будет перекомпилировать код и сделать новый выпуск. Но схема и правила базы данных могут быть внешними по отношению к скомпилированному коду, поэтому они могут меняться без необходимой перекомпиляции, поэтому просто сделайте все данные доступными и не беспокойтесь о новом выпуске. Это сработало, когда компания была новой, а данные, которые мы передавали, были всего лишь несколькими объединенными таблицами; к тому времени, как я ушел, мы передавали сотни таблиц данных, добавляющих в память до нескольких сотен килобайт, хотя правилам требовалось всего несколько бит данных, возможно, из пяти таблиц. Это было медленно и расточительно. Не go по этому маршруту.

Примерно так: когда у вас есть Сотрудник, а у вас есть данные Отдела, внешние - объединение этих двух направлений - это то, что было бы оптимально выполнено в (например) SQL запрос. Такого рода реляционное соединение обычно не требует каких-либо решений, принятых на нем. И если для этого нужны решения (например, если код отдела находится в Dept5, то это означает что-то иное, чем если бы он был в Dept2), тогда несколько правил действительно являются . Но когда речь идет о том же логике c, но в потенциально 5 местах? Не надо делать это в правилах; в этом нет никакой пользы. Сделайте это в Java, а затем передайте результат в правила, чтобы сделать утверждения против.

...