Drools语法进阶「建议收藏」

Drools语法进阶「建议收藏」规则读取和修改数据的不同方法规则配置属性和全局变量规则执行控制机制通过全局变量进行外部交互为了能够与规则引擎环境之外的系统、数据进行交互,Drools提供了很多方法,其中全局变量便是其中一种。globalEShopConfigServiceconfigService;修改工作内存空间中的数据由于Drl是基于描述的编程语言的,所以它没有办法提供一个drl访问另一个drl的方式,所以为了能够将规则拆分为更小的规则,Drools可以在数据发生变化以后重新评估和执行规则。insertru.

大家好,欢迎来到IT知识分享网。

  1. 规则读取和修改数据的不同方法
  2. 规则配置属性和全局变量
  3. 规则执行控制机制

通过全局变量进行外部交互

为了能够与规则引擎环境之外的系统、数据进行交互,Drools提供了很多方法,其中全局变量便是其中一种。

global EShopConfigService configService;

IT知识分享网

修改工作内存空间中的数据

由于Drl是基于描述的编程语言的,所以它没有办法提供一个drl访问另一个drl的方式,所以为了能够将规则拆分为更小的规则,Drools可以在数据发生变化以后重新评估和执行规则。

insert

IT知识分享网rule "Classify Customer - Gold" 
when
$c: Customer( category == Customer.Category.GOLD ) then
           insert(new IsGoldCustomer($c));
end

rule "Classify Item - Low price" when
$i: Item(cost < 10.00) then
         insert(new IsLowRangeItem($i));
end

rule "Suggest gift"
      when
         IsGoldCustomer($c: customer)
         IsLowRangeItem($i: item)
      then
System.out.println("Suggest giving a gift of item "+$i. getName()+" to customer +"$c.getName());
end

对于黄金用户,如果我们有小于10块钱的礼物,则可以赠送一个给他

对于这样一个规则,我们把它拆分为三个小的规则:

  1. 判断黄金用户
  2. 判断礼物
  3. 判断赠送

通过insert关键字修改数据并触发其他规则的执行。

modify和update

对于已存在的数据,通过修改和更新也可以触发规则执行。

rule "Categorize Customer - Gold" when
$c: Customer( category == Customer.Category.NA )
$o: Order(customer == $c, orderLines.size() > 10) then
modify($c){ 
   setCategory(Customer.Category.GOLD);} 
end
IT知识分享网$c.setCategory(Customer.Category.GOLD); 
update($c);

delete和retract(已过时)

删除工作内存中的数据

rule "Init current date"
      when
      then insert(new Date());
   end
   rule "Expire coupons"
      when
$now: Date()
         $cp: Coupon( validUntil before $now )
      then
         delete($cp);
   end
   rule "Execute coupon"
      when
$o: Order()
$cp: Coupon(order == $o) then
System.out.println("We have a coupon for this order!"); end

规则属性

Drools是数据驱动的,但是也提供了规则属性进行规则的控制和过滤。

enable“

rule "simple attribute example"
   enabled false
      when Customer()
then System.out.println("we have a customer"); end

enable设置为false,则对应的规则会被计算但不会被执行。

salience

设置规则的优先级,可以正数或负数,值越大优先级越高

agenda-group

可以对规则进行分组

rule "Promotion: more than 10 pencils get 10% discount" 
agenda-group "promotions"
when
	OrderLine(item.name == "pencil", quantity > 10) 
then
...
end
KieSession ksession = ...; 
ksession.getAgenda().getAgendaGroup("promotions").setFocus(); 
ksession.fireAllRules();

值得注意的是,当规则触发以后,还可以继续通过kcontext定义agenda-group

rule "Done with promotions. Onward with printing invoice" 
salience -100 //last rule of group to run 
agenda-group "promotions"
when
  OrderLine()
then
kcontext.getKnowledgeRuntime().getAgenda(). getAgendaGroup("MAIN").setFocus();
end

控制规则循环

rule "Apply 10% discount on notepads"
when $i: Item(name == "notepad", $sp: salePrice) 
then modify($i) { 
    setSalePrice($sp * 0.9); }
end

modify关键字会触发规则继续执行,陷入死循环。

no-loop

rule "Apply 10% discount on notepads BUT ONLY ONCE" 
no-loop true
when $i: Item(name == "notepad", $sp: salePrice)
then modify($i) { 
    setSalePrice($sp * 0.9); } end

no-loop属性可以防止由于规则自身触发的重新执行,这里要强调的是no-loop只会防止最后一个规则的同一数据引起的重复,如果另外一个规则修改了工作内存中的数据,它还是会第二次执行。

lock-on-active

最快的一种阻止因同一对象被修改的循环触发的方式是添加Lock-on-active属性,它比no-loop有更强的限制循环作用,所有其他规则对数据修改都不会引起循环触发。

标志属性

如果数据很难被修改而无法重新触发规则,我们还可以通过添加标志属性存储检查条件,其他规则可以根据这些属性判断是否要重新执行。

 rule "Add 2% discount for orders larger than $100"
     when $o:
Order(total > 100.00, has100DollarsDiscount == false) then
modify($o){ 
    increaseDiscount(0.02); setHas100DollarsDiscount(true);
} end
   rule "Add 2% discount for orders larger than 15 items"
     when $o:
Order(total > 100.00, has15ItemsDiscount == false) then
modify($o){ 
    increaseDiscount(0.02); setHas15ItemsDiscount(true);
} end

声明类型

Drools的数据模型也可以通过类型声明定义在drl文件中

declare SpecialOrder extends Order
         whatsSoSpecialAboutIt: String
         order: Order
         applicableDiscount: Discount
end

通过java的反射API,我们可以通过KieBase获取声明的类型:

KieSession ksession = ...; //previously initialized FactType type = ksession.getKieBase().getFactType(
"chapter04.declaredTypes", "SpecialOrder"); 
Object instance = type.newInstance();
type.set(instance, "relevance", 2L);
Object attr = type.get(instance, "relevance");

Property-reactive Beans

默认情况下是根据整个对象的属性是否被修改来评估规则是否要重新评估,但有些情况一个对象的某些属性修改不需要引起规则执行,这就需要在数据模型定义上使用property-reactive beans.

 declare PropertyReactiveOrder
          @propertyReactive
          discount: Discount
          totalItems: Integer
          total: Double
end
rule "Larger than 20 items orders are special orders"
          when
              $o: PropertyReactiveOrder(
                  totalItems > 20
              ) @Watch (!discount)
          then
modify ($o) { 
   
setDiscount(new Discount(0.05));
} end

@Watch(discount, total) 只检查diacount和total
@Watch(!discount) 不检查discount
@Watch(!, total)除了total都不检查
@Watch(!
, total, totalItems)除了total,totalitems都不检查

正则

matches

rule "validate customer emails"
when $c: Customer(email not matches
"[A-Za-z0-9-.]+@[A-Za-z0-9-.]+$") 
then $c.setEmail(null); //invalidate email
end

contains memberOf

rule "print orders with pencils in them"
when
$i: Item(name == "pencil")
$ol: OrderLine(item == $i)
$o: Order($ol memberOf orderLines,
              orderLines contains $ol)
then
System.out.println("order with pencils: " + $o); end

from

Drools提供from语句让我们可以在工作空间之外定义特殊的查询空间。

rule "For every notebook order apply points coupon"
when
$o: Order($c: customer, $lines: orderLines) 
OrderLine($item: item) from $lines
Item(name == "notebook") from $item
then
insert(new Coupon($c, $o, CouponType.POINTS));
end

以上这种方式有以下优点:
1、拆分条件更易理解
2、可以对集合类型进一步检索

Collect from objects

以下规则每当插入一个Order后都会执行一次,如果插入50个对象,就会执行50次,效率比较低

rule "Simple order condition"
        when $o: Order()
then System.out.println("order found: " + $o); end

可以使用collect减少到只执行1次

rule "Grouping orders"
when $list: List() from collect(Order())
then
System.out.println("we've found " + $list.size() + " orders");
end

accumulate

有时需要对匹配条件的数据进行转换,accumulate这个关键字可以

rule "10+ items with sale price over 20 get discount"
when
$o: Order($lines: orderLines) 
Number(intValue >= 10) from accumulate(
	OrderLine(
		item.salePrice > 20.00, $q: quantity
	) 
	from $lines, 
	init(int count = 0;), 
	action(count += $q), r
	everse(count -= $q), 
	result(count)
) 
then
	$o.increaseDiscount(0.05);
end

not

工作内存空间中不存在查询可以使用Not

rule "warn about empty working memory"
       when
              not(Order() or Item())
        then
			System.out.println("we don't have elements");
end

exists

exists用来检查工作空间中是否存在满足条件的对象
在这里插入图片描述
左边无论有多少Order只执行一次,右边一个Order执行一次。

forall

forall用来设置满足多个条件

rule "make sure all orders have at least one line"
          when
              exists(Order())
              forall(
					Order()
					Order(orderLines.size() > 0) 
               )
then
	System.out.println("all orders have lines");
end

语法糖

  1. 嵌套访问
OrderLine( item.cost < 30.0, item.salePrice < 25.0 )
OrderLine( item.( cost < 30.0,salePrice < 25.0) )
  1. Inline casts

类型转换

Order(customer#SpecialCustomer.specialDiscount > 0.0)

Trait

traits可以被看作一些可以动态添加到对象的属性,要使用trait,需要以下两步:
1、定义trait

declare trait KidFriendly
                 kidsAppeal: String
end

2、对类添加@Traitable注解

使用don 关键字添加 添加traits

rule "toy items are kid friendly" 
no-loop
          when
            $i: TraitableItem(name contains "toy")
          then
            KidFriendly kf = don($i, KidFriendly.class); 
            kf.setKidAppeal("can play with it");
end

使用关键字shed去除traits

Object o = shed( $traitedObject, KidFriendly.class)

逻辑插入

逻辑插入将插入的数据和条件绑定,插入的条件不再满足的时候,数据就会在内存中自动被删除

rule "determine large orders"
       when $o: Order(total > 150)
       then insertLogical(new IsLargeOrder($o));
end

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/11678.html

(0)

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注

关注微信