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



我有一个场景,输入中的数据对于一个事实具有不同的列,即的转置数据

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查找?

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

谢谢!

因此,基本上您有一个员工,他们的部门可以列在五个位置中的任何一个。解决这一问题的最佳方法是在启动规则之前先弄清楚部门所在的位置,然后修改传递到规则中的对象。您不受传递到规则中的对象类型的限制,只要它们序列化正常即可;如果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方法,因为此类调用无法优化。当你像Employee(department == 6)那样进行过滤时,Drools可以对断言进行大量优化,以使你的规则更快地启动。但是,如果您正在调用一个Java方法,这就像Drools引擎的一个黑匣子;它不知道Java方法将要做什么,所以它必须让它按原样进行评估,而不是为了更快地进行工作。

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

我在一家公司工作,该公司会将数据库结果直接传递到规则中。逻辑是代码已经编译,所以如果需要对规则输入对象进行更改,则需要重新编译代码并进行新的发布。但是数据库模式和规则可能在编译后的代码之外,因此它们可以在不需要重新编译的情况下进行更改,所以只需提供所有数据,而不必为新版本而烦恼。当公司还是新公司时,这种方法就奏效了,我们传递的数据只是几个连接的表;当我离开的时候,我们正在传递数百个数据表,这些数据表的内存加起来高达几百KB,尽管规则只需要五个表中的几位数据。它既慢又浪费。不要沿着这条路走。

类似于这样的情况,您有一个Employee和一个Department外部数据——将两者连接起来是在(例如(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

这里的"收集"功能确保员工记录不重复,然后可以找到各个适用的部门。

最新更新