Drools-如何在THEN子句中访问对象

Drools-如何在THEN子句中访问对象,drools,Drools,我有一个场景,输入中的数据对于一个事实有不同的列,例如,对于 EmployeeID | EmpDept1 | EmpDept2 | EmpDept3 | EmpDept4 | EmpDept5 现在我也有了一个查找部门表 DeptId | DeptName 对于我来说,进行查找的一种方法是创建5条规则,如: rule "Lookup dept-1 data" when e: EmployeeData() d: DeptData(deptId == $e.EmpDept1) t

我有一个场景,输入中的数据对于一个事实有不同的列,例如,对于

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条规则,在我的例子中还有更多。有没有一种方法可以访问THEN子句中的DeptData,然后编写JAVA查找

或者如果有其他好办法,请告诉我


谢谢

所以基本上你有一个员工,他们的部门可以在五个地方中的任何一个列出。解决这个问题的最佳方法是在触发规则之前找出部门所在的位置,然后修改传递到规则中的对象。您不受传递到规则中的对象类型的限制,只要它们序列化ok;如果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();
}
然后,您可以编写输入部门id的规则:

rule "Employee is in department 6"
when
  Employee( departmentId == 6 )
then
  // do something
end
或者,您可以从when子句调用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方法,因为这样的调用无法优化。当您执行Employeedepartment==6之类的过滤时,Drools可以对断言进行大量优化,以加快规则的启动速度。但是如果你调用一个Java方法,那就像是Drools引擎的一个黑匣子;它不知道Java方法将要做什么,所以它必须让它按原样进行计算,而不是做一些使它更快的工作

此外,通常也不建议将任意数据传递到规则集中。仅传入规则启动所需的数据。当从其他数据源转换时,例如从SQL查询结果或从电子表格转换时,解析您实际需要的其他数据部分,并将解析后的输入对象传递到规则中

我在一家将数据库结果直接传递到规则中的公司工作。逻辑上,代码是编译的,因此如果需要对规则输入对象进行更改,则需要重新编译代码并执行新版本。但是数据库模式和规则可能在编译代码之外,因此它们可以在不需要重新编译的情况下进行更改,所以只需使所有数据可用,而不用担心新版本。当公司是新的,我们传递的数据只有几个连接的表时,这就起作用了;当我离开时,我们传入了数百个数据表,在内存中总计数百KB,尽管规则只需要五个表中的几位数据。这既慢又浪费。不要走这条路


类似这样的情况下,您有一个员工,您有一个外部部门数据-将这两个数据连接在一起是最好的方法,例如SQL查询。这种关系连接通常不需要做出任何决定。如果它确实需要决策,例如,如果部门代码在Dept5中,那么它意味着与在Dept2中不同的东西,那么多个规则实际上是合适的。但当它只是一个逻辑相同的问题,但在潜在的5个地方?不要费心按照规则去做;这没有好处。在Java中执行此操作,然后将结果传递到规则中,以对其进行断言

我用collect解决了这个问题

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

此处的“收集”功能可确保员工记录不会重复,然后可以找到各个适用的部门。

谢谢您的回复。我这里的问题是,员工也可以属于多个部门,有多少部门也不是固定的。在这种情况下,我只能用Java来完成这项工作。因此,即使我在内存中有整个部门表,我也需要一种方法来查找它,因为员工是部门的一部分。现在,一种方法是编写尽可能多的规则,另一种方法是通过department对象进行简单的循环,每次都查找department。有没有第二种方法?我的意思是把整个部门的桌子从RHS传过来,这样我就可以循环通过了。嗯,是吗?把它放到工作记忆里?不过,我仍然不确定您为什么要在规则中这样做。我也不知道为什么员工可以是多个部门的一部分这一事实是一个问题。这也确保了即使部门数据中没有部门,也可以进行查找。如果任何部门为空,则规则将不返回0