Drools Accumulate 语法解析及使用

一、Accumulate语法分析

accumulate( <source pattern>; <functions> [;<constraints>] )

例如,计算给定传感器的最低、最高和平均温度读数的规则,如果最低温度低于20C,而平均温度超过70C,则会发出警报,可以用累加写成:

rule "Raise alarm"
when
    $s : Sensor()
    accumulate( Reading( sensor == $s, $temp : temperature );
                $min : min( $temp ),
                $max : max( $temp ),
                $avg : average( $temp );
                $min < 20, $avg > 70 )
then
    // raise the alarm
end

在上面的例子中,min、max和average是累加函数,将计算每个传感器所有读数上的最小、最大和平均温度值。

二、Drools附带的内置的累加功能,包括:

  • average

  • min

  • max

  • count

  • sum

  • variance

  • standardDeviation

  • collectList

  • collectSet

三、替代语法:带有返回类型的单个函数

累加语法随着时间的推移而发展,其目标是变得更加紧凑和富有表现力。不过,Drools仍然支持以前的语法以实现向后兼容性。

如果规则在给定的累加上使用单个累加函数,则可以为result对象添加一个模式,并使用“from”关键字将其链接到累加结果。例如:对100美元以上的订单给予10%折扣的规则可以这样写:

rule "Apply 10% discount to orders over US$ 100,00"
when
    $order : Order()
    $total : Number( doubleValue > 100 )
             from accumulate( OrderItem( order == $order, $value : value ),
                              sum( $value ) )
then
    // apply discount to $order
end

在上面的例子中,累加元素只使用一个函数(sum),因此规则作者选择显式地为累加函数(Number)的结果类型编写一个模式,并在其中编写约束。在使用这种语法时,与前面介绍的紧凑语法相比,没有任何问题,只是有点冗长。还请注意,不允许在同一个累加语句中同时使用返回类型和函数绑定。

执行编译时检查是为了确保使用“from”关键字的模式可以从使用的累加函数的结果中分配。

在上面的例子中,“$total”被绑定到collect sum()函数返回的结果。

但是,另一个例子是,如果累加函数的结果是一个集合,那么“from”仍然绑定到单个结果,并且它不会迭代:

rule "Person names"
when
  $x : Object() from accumulate(MyPerson( $val : name );
                                collectList( $val ) )
then
  // $x is a List
end

绑定的“$x: Object()”是列表本身,由使用的collectList累加函数返回。

这是一个需要强调的重要区别,因为“from”关键字也可以单独用于累加,以遍历集合的元素:

rule "Iterate the numbers"
when
    $xs : List()
    $x : Integer() from $xs
then
  // $x matches and binds to each Integer in the collection
end

尽管出于向后兼容性的目的,仍然支持这种语法,但是出于这个和其他原因,我们鼓励规则作者使用而不是使用累加CE首选语法,以避免任何潜在的陷阱,如下面的示例所述。

四、使用内联自定义代码进行累积(推荐)

语法:

<result pattern> from accumulate( <source pattern>,
                                  init( <init code> ),
                                  action( <action code> ),
                                  reverse( <reverse code> ),
                                  result( <result expression> ) )

每个要素的含义如下:

<srouce pattern>:源模式是一个常规模式,引擎将尝试匹配每个源对象。

<init code>:这是所选方言中的一个语义代码块,在遍历源对象之前,将对每个元组执行一次。

<action code>:这是所选方言中的一个语义代码块,将为每个源对象执行。

<reverse code>:这是所选方言中可选的语义代码块,如果存在,将为不再匹配源模式的每个源对象执行。这个代码块的目的是撤销在块中所做的任何计算,这样引擎就可以在修改或删除源对象时进行递减计算,极大地提高了这些操作的性能。

<result expression>:这是在所选方言中的一个语义表达式,在遍历所有源对象之后执行。

<result pattern>:这是一个规则模式,引擎试图匹配从返回的对象。如果匹配,则累加条件元素的计算结果为true,然后引擎继续计算规则中的下一个CE。如果不匹配,累加CE的值将为false,引擎将停止为该规则计算CEs。

例子:

rule "Apply 10% discount to orders over US$ 100,00"
when
    $order : Order()
    $total : Number( doubleValue > 100 )
             from accumulate( OrderItem( order == $order, $value : value ),
                              init( double total = 0; ),
                              action( total += $value; ),
                              reverse( total -= $value; ),
                              result( total ) )
then
    // apply discount to $order
end

在上面的示例中,对于工作内存中的每个订单,引擎将执行初始化总变量为零的init代码。然后,它将遍历该订单的所有OrderItem对象,为每个对象执行操作(在本例中,它将把所有项的值加到total变量中)。在遍历所有OrderItem对象之后,它将返回与结果表达式对应的值(在上面的示例中,是变量total的值)。最后,引擎将尝试将结果与数字模式匹配,如果double值大于100,则规则将触发。

本例使用Java作为语义方言,因此,请注意在init、action和reverse代码块中必须使用分号作为语句分隔符。结果是一个表达式,因此,它不承认“;”。如果用户使用任何其他方言,他必须遵守该方言的特定语法。

如前所述,反向代码是可选的,但强烈建议用户编写它,以便从更新和删除性能的改进中获益。

rule "Accumulate using custom objects"
when
    $person   : Person( $likes : likes )
    $cheesery : Cheesery( totalAmount > 100 )
                from accumulate( $cheese : Cheese( type == $likes ),
                                 init( Cheesery cheesery = new Cheesery(); ),
                                 action( cheesery.addCheese( $cheese ); ),
                                 reverse( cheesery.removeCheese( $cheese ); ),
                                 result( cheesery ) );
then
    // do something
end

五、实战案例

(1)获取10分钟订单数超过100的订单信息

rule "获取10分钟订单数超过100的订单信息"
    when
        $t1: OrderInfo()
        $list: List(size > 99) from accumulate(
            $t2: OrderInfo(
                this != $t1
                this after[ 0s, 10m ] $t1
            ),
            init(List list = new ArrayList();),
            action(list.add($t2);)
            result(list)
        )
    then
        // do something
end

(2)10分钟出现3次错误

rule "10分钟出现3次错误"
    when
        $count: Number(intValue >= 3) from accumulate(
            $temp: LogInfo(type == "error") over window:time( 10m ),
            count($temp)
        )
    then
        // do something
end

(3)1分钟定时统计出现的错误数

rule "1分钟定时统计出现的错误数"
    timer(cron: 0 0/1 * * * ?)
    when
        $count: Number() from accumulate(
            $temp: LogInfo(type == "error") over window:time( 1m ),
            count($temp)
        )
    then
        // do something
end

一起学习

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

magic_kid_2010

你的支持将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值