我目前正在对Java批处理程序进行一些修复,该批处理程序运行一组Drools
(不错!)规则。
我要解决的规则是这样:
rule "Insert a too old condition"
salience -1
when
$person : Person()
$tooOldInstant : DateTime() from now.minusDays(10)
DateTime( this < $tooOldInstant ) from accumulate (
LastData( $date : lastDate ) from $person.personLastDatas,
maxValue($date)
)
then
insert(new Condition("submitTooOldCondition"));
end
用于简化的地方Person
是具有 personLastDatas Set<LastData>
的简单bean,而LastData
具有org.joda.time.DateTime
lastDate 属性。
问题:我如何在$person.personLastDatas
为null的情况下插入新条件?
类似的东西:
rule "Insert a too old condition modified"
salience -1
when
$person : Person()
$tooOldInstant : DateTime() from now.minusDays(10)
$maxLastDate : DateTime() from accumulate (
LastData( $date : lastDate ) from $person.personLastDatas,
maxValue($date)
)
($maxLastDate == null || $maxLastDate < $tooOldInstant)
then
insert(new Condition("submitTooOldCondition"));
end
答案 0 :(得分:1)
您应该有两条规则,一条用于空条件,另一条用于比较日期。
这是空条件规则;它会验证Person是否存在但没有personLastDatas
属性:
rule "Insert a too old condition modified - null case"
salience -1
when
$person: Person( personLastDatas == null )
then
insert(new Condition("submitTooOldCondition"));
end
您现有的规则足以进行日期比较检查。
通常,如果您发现自己尝试在规则的任一侧执行复杂的if-else逻辑,则很好地表明您应该有两个规则。由于这两个规则不能同时成立,因此只能插入一个这种类型的条件。
话虽如此,如果您使用的是现代版本的流口水,则可以使用有条件的命名空间后果。 documentation对此进行了详细介绍(我已经链接了7.37.0.Final;最新的7.30+版本大多数都具有此功能。)以下是您的规则的示例:
rule "Insert a too old condition"
salience -1
when
$person : Person( $lastDatas: personLastDatas )
if ( $lastDatas == null ) break[noData]
$tooOldInstant : DateTime() from now.minusDays(10)
DateTime( this < $tooOldInstant ) from accumulate (
LastData( $date : lastDate ) from $person.personLastDatas,
maxValue($date)
)
then
insert(new Condition("submitTooOldCondition"));
then[noData]
// any special logic for the null case goes here
insert(new Condition("submitTooOldCondition"));
end
(这是伪代码;我在这台计算机上没有drools项目,但应该类似。)
虽然很难理解,但基本上该语法将使您能够处理这种重复/部分共享的大小写规则。通常建议在以下情况下使用它们:两条规则,一条规则扩展另一条规则,因此,一部分通用条件可以触发一个结果,而整套条件可以触发另一个结果。这不是您所拥有的,但是可以针对您的用例对功能进行混用。
关键字break
告诉引擎,一旦满足条件,则停止评估左侧;还有一个do
关键字,可以继续进行评估。
答案 1 :(得分:1)
选项1
rule "Insert a too old condition"
salience -1
when
Person(personLastDatas == null)
or
$person : Person()
and $tooOldInstant : DateTime() from now.minusDays(10)
and DateTime( this < $tooOldInstant ) from accumulate (
LastData( $date : lastDate ) from $person.personLastDatas,
maxValue($date)
)
then
System.out.println("submitTooOldCondition");
end
选项2
使聚合函数按您所需的方式工作。 对于您在规则中表示的业务,应将null DateTime视为可能的最小值。如果所有其他规则都为true,则可以将此逻辑封装在maxValue
函数中。
public Object getResult(HashSet<DateTime> context) throws Exception {
return context.isEmpty() ? new DateTime(0) /*null*/ : context.iterator().next();
}
在上述逻辑之上,您的原始规则将按预期工作,而无需进行任何修改。
测试
@DroolsSession(resources = "classpath:/test.drl")
public class PlaygroundTest {
@Rule
public DroolsAssert drools = new DroolsAssert();
@Test
@TestRules(expectedCount = { "2", "Insert a too old condition" })
public void testIt() {
drools.setGlobal("now", now());
drools.insertAndFire(new Person(newHashSet(new LastData(now().minusDays(100)), new LastData(now().minusDays(5)))));
drools.insertAndFire(new Person(newHashSet(new LastData(now().minusDays(100)), new LastData(now().minusDays(15)))));
drools.insertAndFire(new Person(null));
}
}
测试输出
00:00:00 --> inserted: Person[personLastDatas=[org.droolsassert.LastData@25243bc1, org.droolsassert.LastData@1e287667]]
00:00:00 --> fireAllRules
00:00:00 --> inserted: Person[personLastDatas=[org.droolsassert.LastData@76f10035, org.droolsassert.LastData@5ab9b447]]
00:00:00 --> fireAllRules
00:00:00 <-- 'Insert a too old condition' has been activated by the tuple [Person, DateTime, DateTime]
submitTooOldCondition
00:00:00 --> inserted: Person[personLastDatas=<null>]
00:00:00 --> fireAllRules
00:00:00 <-- 'Insert a too old condition' has been activated by the tuple [Person]
submitTooOldCondition
功能来源
public class MaxValueAccumalateFunction implements AccumulateFunction<HashSet<DateTime>> {
@Override
public void writeExternal(ObjectOutput out) throws IOException {
}
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
}
@Override
public HashSet<DateTime> createContext() {
return new HashSet<>();
}
@Override
public void init(HashSet<DateTime> context) throws Exception {
}
@Override
public void accumulate(HashSet<DateTime> context, Object value) {
if (context.isEmpty() || context.iterator().next().isBefore((DateTime) value)) {
context.clear();
context.add((DateTime) value);
}
}
@Override
public void reverse(HashSet<DateTime> context, Object value) throws Exception {
}
@Override
public Object getResult(HashSet<DateTime> context) throws Exception {
return context.isEmpty() ? new DateTime(0) /*null*/ : context.iterator().next();
}
@Override
public boolean supportsReverse() {
return false;
}
@Override
public Class<?> getResultType() {
return null;
}
}
规则源
import org.joda.time.DateTime;
import accumulate org.droolsassert.MaxValueAccumalateFunction maxValue;
global DateTime now;
rule "Insert a too old condition"
salience -1
when
Person(personLastDatas == null)
or
$person : Person()
and $tooOldInstant : DateTime() from now.minusDays(10)
and DateTime( this < $tooOldInstant ) from accumulate (
LastData( $date : lastDate ) from $person.personLastDatas,
maxValue($date)
)
then
System.out.println("submitTooOldCondition");
end