drools学习笔记-rule组织方式

rule的salience(突出性)属性,定义rule的执行顺序

属性值越高,执行的优先级越高。

RuleB虽然定义在RuleA的后边,但salience值比较高,所以总优先执行。

rule "RuleA"
salience 95
when
    $fact : MyFact( field1 == true )
then
    System.out.println("Rule2 : " + $fact);
    update($fact);
end

rule "RuleB"
salience 100
when
   $fact : MyFact( field1 == false )
then
   System.out.println("Rule1 : " + $fact);
   $fact.setField1(true);
   update($fact);
end

rule group的agenda属性,定义一组rule和其他组的执行顺序

通过设置agenda-group的属性,将一组rule绑定到一个组中。
在同一时刻,只有一个组被focus,其中的rule将会被执行。
可以为rule设置auto-focus属性,那么rule所在的组会自动被focus。
默认情况下,所有没有设置group的rule都会放到"MAIN"组中。如果其他组也没有设置focus,那么"MAIN"中的将会在所有的组之前执行。
例子:

rule "Increase balance for credits"
  agenda-group "calculation"
when
  ap : AccountPeriod()
  acc : Account( $accountNo : accountNo )
  CashFlow( type == CREDIT,
            accountNo == $accountNo,
            date >= ap.start && <= ap.end,
            $amount : amount )
then
  acc.balance  += $amount;
end
rule "Print balance for AccountPeriod"
  agenda-group "report"
when
  ap : AccountPeriod()
  acc : Account()
then
  System.out.println( acc.accountNo +
                      " : " + acc.balance );
end

report必须在calculation之前执行,且这两个分组在所有的rule之前执行,则需要在java中如下设置。

Agenda agenda = ksession.getAgenda();
agenda.getAgendaGroup( "report" ).setFocus();
agenda.getAgendaGroup( "calculation" ).setFocus();
ksession.fireAllRules();

也可以取消一个组内所有rule的执行。

ksession.getAgenda().getAgendaGroup( "Group A" ).clear();

activation-group控制一组rule的排他性

activation-group下只有一个符合条件的rule执行。

rule "Print balance for AccountPeriod1"
  activation-group "report"
when
  ap : AccountPeriod1()
  acc : Account()
then
  System.out.println( acc.accountNo +
                      " : " + acc.balance );
end
rule "Print balance for AccountPeriod2"
  activation-group "report"
when
  ap : AccountPeriod2()
  acc : Account()
then
  System.out.println( acc.accountNo +
                      " : " + acc.balance );
end

只会执行一个。

rule执行模式以及drools引擎的线程安全

被动模式

默认模式。
明确调用fireAllRules()触发rule。
Drools引擎中的被动模式最适合于需要直接控制规则评估和执行的应用程序,或者适合于在Drools引擎中使用伪时钟实现的复杂事件处理(CEP)应用程序。

KieSessionConfiguration config = KieServices.Factory.get().newKieSessionConfiguration();
config.setOption( ClockTypeOption.get("pseudo") );
KieSession session = kbase.newKieSession( conf, null );
SessionPseudoClock clock = session.getSessionClock();

session.insert( tick1 );
session.fireAllRules();

clock.advanceTime(1, TimeUnit.SECONDS);
session.insert( tick2 );
session.fireAllRules();

clock.advanceTime(1, TimeUnit.SECONDS);
session.insert( tick3 );
session.fireAllRules();

session.dispose();

主动模式

用户调用fireUntilHalt()将会开启主动模式。程序会不断处理,直到调用了halt()。
Drools引擎中的Active模式最适合将规则评估和执行的控制权委托给Drools引擎的应用程序,或者适合使用Drools引擎中的实时时钟实现的复杂事件处理(CEP)应用程序。

KieSessionConfiguration config = KieServices.Factory.get().newKieSessionConfiguration();
config.setOption( ClockTypeOption.get("realtime") );
KieSession session = kbase.newKieSession( conf, null );

new Thread( new Runnable() {
  @Override
  public void run() {
      session.fireUntilHalt();
  }
} ).start();

session.insert( tick1 );

... Thread.sleep( 1000L ); ...

session.insert( tick2 );

... Thread.sleep( 1000L ); ...

session.insert( tick3 );

session.halt();
session.dispose();

尽管应该避免同时使用fireAllRules()和fireUntilHalt()调用,特别是来自不同线程的调用,但是Drools引擎可以使用线程安全逻辑和内部状态机安全地处理这种情况。如果正在调用一个fireAllRules(),并且您调用了fireUntilHalt(),那么Drools引擎将继续以被动模式运行,直到fireAllRules()操作完成,然后以主动模式启动以响应fireUntilHalt()调用。

Fact在Drools引擎中的传播模式

  • Lazy模式:
    默认模式。批处理方式。
    fact的处理顺序不能保证和输入顺序相同。
  • Immediate:
    fact在输入的时候,立即传播出去。可以保证顺序性。
  • Eager:
    在rule执行之前,批量传播。

可以通过@Propagation()改变单个rule的传播模式。type可以是LAZY, IMMEDIATE, 或者 EAGER。

query Q (Integer i)
    String( this == i.toString() )
end

rule "Rule" @Propagation(IMMEDIATE)
  when
    $i : Integer()
    ?Q( $i; )
  then
    System.out.println( $i );
end

议程估算过滤器

调用fireAllRules()的时候,可以指定过滤器,过滤哪些rule执行。

ksession.fireAllRules( new RuleNameEndsWithAgendaFilter( "Test" ) );

默认过滤器包括名称匹配,名称前缀匹配,名称后缀匹配等。

DRL rule集合中的rule unit

rule unit 是数据源,全局变量,DRL rule的组,为了特定的目的组织起来。
rule unit是对agenda group以及activation group的加强。
定义rule unit:

package org.mypackage.myunit;

public static class AdultUnit implements RuleUnit {
    private int adultAge;
    private DataSource<Person> persons;

    public AdultUnit( ) { }

    public AdultUnit( DataSource<Person> persons, int age ) {
        this.persons = persons;
        this.age = age;
    }

    // A data source of `Persons` in this rule unit:
    public DataSource<Person> getPersons() {
        return persons;
    }

    // A global variable in this rule unit:
    public int getAdultAge() {
        return adultAge;
    }

    // Life-cycle methods:
    @Override
    public void onStart() {
        System.out.println("AdultUnit started.");
    }

    @Override
    public void onEnd() {
        System.out.println("AdultUnit ended.");
    }
}

persons是Person类型fact的集合。整个rule unit的数据源。
adultAge是一个全局变量,所有的rule都可以引用。
onStart() onEnd()是rule unit的生命周期接口。

MethodInvoked when
onStart()Rule unit execution starts
onEnd()Rule unit execution ends
onSuspend()Rule unit execution is suspended (used only with runUntilHalt())
onResume()Rule unit execution is resumed (used only with runUntilHalt())
onYield(RuleUnit other)The consequence of a rule in the rule unit triggers the execution of a different rule unit

默认,所有的rule都在DRL文件同名的rule unit下。如果DRL文件的包路径和名字,和一个实现了Rulenit接口的类相同,那么DRL下所有的rule都会加入这个unit。
可以通过unit关键字更改unit的名字。

package org.mypackage.myunit
unit AdultUnit

rule Adult
  when
    $p : Person(age >= adultAge) from persons
  then
    System.out.println($p.getName() + " is adult and greater than " + adultAge);
end

可以通过更简单的方式OOPath访问数据源。

package org.mypackage.myunit
unit AdultUnit

rule Adult
  when
    $p : /persons[age >= adultAge]
  then
    System.out.println($p.getName() + " is adult and greater than " + adultAge);
end

Unit执行方法。

// Create a `RuleUnitExecutor` class and bind it to the KIE base:
KieBase kbase = kieContainer.getKieBase();
RuleUnitExecutor executor = RuleUnitExecutor.create().bind( kbase );

// Create the `AdultUnit` rule unit using the `persons` data source and run the executor:
RuleUnit adultUnit = new AdultUnit(persons, 18);
executor.run( adultUnit );

除了创建一个Rule Unit的实例,也可以通过绑定的方式传入数据。

executor.bindVariable( "persons", persons );
        .bindVariable( "adultAge", 18 );
executor.run( AdultUnit.class );

可以通过注解@UnitVar来更改绑定接口中的key。

package org.mypackage.myunit;

public static class AdultUnit implements RuleUnit {
    @UnitVar("minAge")
    private int adultAge = 18;

    @UnitVar("data")
    private DataSource<Person> persons;
}
executor.bindVariable( "data", persons );
        .bindVariable( "minAge", 18 );
executor.run( AdultUnit.class );
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值