Drools + Hibernate:需要在规则中用 OR 条件模拟 Left Outer Join
Drools + Hibernate: Need to simulate Left Outer Join with OR condition in rule
使用下面的规则,我尝试使用具有 OR 逻辑条件的规则来匹配帐户。在这种情况下,我有一个 table 的账户和一个 table 这些账户的保险记录。并非所有帐户都有保险记录。 Hibernate DAO 对象存在并且存在从帐户到保险的关联。我没有观察到这条规则的预期行为。在这种情况下,我希望帐户 1、2、3 和 4 匹配此规则,因为该规则应匹配状态为 "Inactive" 的任何帐户或保险 CURRENT_IND 值为 [= 的任何帐户21=]。但是,只有帐户 2 和 4 符合规则。仅当帐户具有保险记录时,该帐户才会匹配规则。我想要状态为 'Inactive' 的所有帐户记录,无论其保险记录是否存在。
我目前正在使用 Drools 5.6.10.FINAL 和 Hibernate 3.6.0.
进行测试
是否可以使用带 Drools 的 Hibernate 创建这样的规则?是什么导致规则过滤保险记录的存在?
package com.app.Testing
import com.app.abilities.RuleBuilder.EvalObject;
import com.app.dao.Insurance;
import com.app.dao.Account;
rule "Null Test"
when
$V1 : Account( )
$V2 : Insurance( ) from $V1.getInsurance()
$V3 : EvalObject(
$V2.getCurrentInd == "N" ||
$V1.getStatus == "Inactive"
)
then
reply.getReplyList().add("Null Test");
end
示例数据:
Account:
ACCT_ID STATUS
1 Inactive
2 Inactive
3 Inactive
4 Active
5 Active
Insurance:
ID CURRENT_IND
2 N
4 N
5 Y
完全没有必要使用 "from" 访问某些事实的现成可用字段 - 您可以通过绑定变量或 getter 访问。这就是导致问题的原因:空值不能 "frommed" 到模式中,因此任何具有保险 == null 的帐户都将阻止进一步评估。
此外,我发现使用完全事实 (EvalObject) 来编写布尔值而不是巴洛克式的。即使您必须使用 oh-so-terrible Java 语法,一个简单的 eval 也应该做得很好。
总而言之,以下规则对您的所有四个帐户都有效:
rule "Better Test"
when
$V1: Account( $sta: status, $ins: insurance )
eval( $sta.equals( "Inactive" ) ||
$ins != null && $ins.getCurrentInd().equals( "N" ) )
then
System.out.println("Better Test " + $V1.getId() );
end
当然,逻辑是一件非常美妙的事情,如果应用得当,它会随着皮带的拉动而变化。因此,您还可以使用一些规则:
rule "Third Test A"
when
$V1: Account( $sta: status == "Inactive" )
then
System.out.println("Third Test A " + $V1.getId() );
end
rule "Third Test B"
when
$V1: Account( $sta: status == "Active" )
Insurance( currentInd == "N" ) from $V1.getInsurance()
then
System.out.println("Third Test B " + $V1.getId() );
end
"Ahh",我听到你说,"he's making me use two rules for what can be done with one? Duplicate the RHS code? Phooey!"
不,不是我:这只是通往决赛的桥梁。这个怎么样:
rule "Fourth Test"
when
$V1: Account( $sta: status == "Inactive" )
or
($V1: Account( $sta: status == "Active" )
and
Insurance( currentInd == "N" ) from $V1.getInsurance()
)
then
System.out.println("Fourth Test " + $V1.getId() );
end
编辑 如果一个帐户可能与任意数量的保险事实相关联(即 getInsurance returns a Collection<Insurance>
),最后三个规则仅适用一样好。但是,他们将为 currentInd == "N"
处的每个关联保险开火。要将其减少为单个激活,请在 Insurance 模式前加上 exists(或 not 以获得稍微不同的效果)。
考虑将受抚养人 objects(保险)也作为事实考虑总是值得的。此外,从 child 到 parent(帐户)的 link 可能会改善问题。
使用下面的规则,我尝试使用具有 OR 逻辑条件的规则来匹配帐户。在这种情况下,我有一个 table 的账户和一个 table 这些账户的保险记录。并非所有帐户都有保险记录。 Hibernate DAO 对象存在并且存在从帐户到保险的关联。我没有观察到这条规则的预期行为。在这种情况下,我希望帐户 1、2、3 和 4 匹配此规则,因为该规则应匹配状态为 "Inactive" 的任何帐户或保险 CURRENT_IND 值为 [= 的任何帐户21=]。但是,只有帐户 2 和 4 符合规则。仅当帐户具有保险记录时,该帐户才会匹配规则。我想要状态为 'Inactive' 的所有帐户记录,无论其保险记录是否存在。
我目前正在使用 Drools 5.6.10.FINAL 和 Hibernate 3.6.0.
进行测试是否可以使用带 Drools 的 Hibernate 创建这样的规则?是什么导致规则过滤保险记录的存在?
package com.app.Testing
import com.app.abilities.RuleBuilder.EvalObject;
import com.app.dao.Insurance;
import com.app.dao.Account;
rule "Null Test"
when
$V1 : Account( )
$V2 : Insurance( ) from $V1.getInsurance()
$V3 : EvalObject(
$V2.getCurrentInd == "N" ||
$V1.getStatus == "Inactive"
)
then
reply.getReplyList().add("Null Test");
end
示例数据:
Account:
ACCT_ID STATUS
1 Inactive
2 Inactive
3 Inactive
4 Active
5 Active
Insurance:
ID CURRENT_IND
2 N
4 N
5 Y
完全没有必要使用 "from" 访问某些事实的现成可用字段 - 您可以通过绑定变量或 getter 访问。这就是导致问题的原因:空值不能 "frommed" 到模式中,因此任何具有保险 == null 的帐户都将阻止进一步评估。
此外,我发现使用完全事实 (EvalObject) 来编写布尔值而不是巴洛克式的。即使您必须使用 oh-so-terrible Java 语法,一个简单的 eval 也应该做得很好。
总而言之,以下规则对您的所有四个帐户都有效:
rule "Better Test"
when
$V1: Account( $sta: status, $ins: insurance )
eval( $sta.equals( "Inactive" ) ||
$ins != null && $ins.getCurrentInd().equals( "N" ) )
then
System.out.println("Better Test " + $V1.getId() );
end
当然,逻辑是一件非常美妙的事情,如果应用得当,它会随着皮带的拉动而变化。因此,您还可以使用一些规则:
rule "Third Test A"
when
$V1: Account( $sta: status == "Inactive" )
then
System.out.println("Third Test A " + $V1.getId() );
end
rule "Third Test B"
when
$V1: Account( $sta: status == "Active" )
Insurance( currentInd == "N" ) from $V1.getInsurance()
then
System.out.println("Third Test B " + $V1.getId() );
end
"Ahh",我听到你说,"he's making me use two rules for what can be done with one? Duplicate the RHS code? Phooey!"
不,不是我:这只是通往决赛的桥梁。这个怎么样:
rule "Fourth Test"
when
$V1: Account( $sta: status == "Inactive" )
or
($V1: Account( $sta: status == "Active" )
and
Insurance( currentInd == "N" ) from $V1.getInsurance()
)
then
System.out.println("Fourth Test " + $V1.getId() );
end
编辑 如果一个帐户可能与任意数量的保险事实相关联(即 getInsurance returns a Collection<Insurance>
),最后三个规则仅适用一样好。但是,他们将为 currentInd == "N"
处的每个关联保险开火。要将其减少为单个激活,请在 Insurance 模式前加上 exists(或 not 以获得稍微不同的效果)。
考虑将受抚养人 objects(保险)也作为事实考虑总是值得的。此外,从 child 到 parent(帐户)的 link 可能会改善问题。