• drools_12_lhs


    LHS (left hand side) 部分

    Drools 作为规则引擎, 最重要的功能就是完成 pattern match, 即按照 LHS 对工作内存的fact进行匹配, 老版Drools使用的匹配算法是RETE(读音[reetee]), 该算法的核心策略是分而治之+以空间换时间, 基于该算法, 即使是有大量的rule和fact需要匹配, 规则执行的时间复杂度也是可以接受的, 当然内存占用会比较高.

    完整的 LHS 语法比较复杂, 可参考Drools Documentation
    但基本语法是非常简单, 一般情况下只需要基本语法就足够了.

    绑定变量

    下面就是一个常用的LHS, 包含两个关联对象的匹配, 定义了两个对象级别绑定变量, 一个属性级的绑定变量.

    when
       $customer:Customer(age>20 && location=="China" &&  gender=="male", $age:age)
       $order: Order(customer==$customer, price>1000)
    then 
       ...
    
    

    约束中的操作符:

    约束中常用的操作符号有:

    • < 和 <= 和 > 和 >= 符号, 这些与java含义一致, 可以对数值和字符串进行对比
    • == , 这个是null安全的equal, 和java的 == 含义不同.
    • !=, 这个是null安全的不等于符号, 和java中的 != 含义不同
    • contains , 包含, 可以判断字符串包含子串, 也可以判断集合/数组包含元素
    • not contains, 不包含
    • memberOf, 属于, 注意 Of 要大写. 和 contains 语义正好相反.
    • not memberOf, 不属于,注意 Of 要大写.
    • matches, 正则匹配
    • not matches, 正则不匹配
    • instanceOf, 类型属于
    • not instanceOf, 类型不属于
    • in , 这个作用和 memberOf 类似, 写法同SQL的in子句
    • not in, 这个和 not memberOf 类似, 写法同SQL的 not in 子句
    • && ,逻辑与, 和java的含义
    • || , 逻辑或, 和java的含义

    逗号分隔符

    逗号分隔符可以分隔两个条件, 其作用等同于 &&, 但优先级比较 && 和 || 要低, 一般情况下, 推荐使用逗号分隔符因为其可读性更好.

    字符串专用运算符 str

    $order:Order(name str[startsWith] "A")
    $order:Order(name str[endsWith] "A")
    $order:Order(name str[length] 15)
    

    分组条件元素(conditional element)

    分组条件元素不同于普通的操作符, 普通操作符用在field上, 而, 分组条件元素被用于pattern之上.

    • and
      and 分组条件元素的作用是logic join, 连接两个pattern, 要求同时满足两个pattern, 一般我们会省略这里的 and 关键词.
    when
      Cheese(type=="IceCream", $cheeseType:type) 
      and //这里的and可以被省略
      Person(favoriteCheese==$cheeseType)
    then 
       ...
    
    • or
      or 分组条件元素的作用是logic split, 连接两个pattern, 形成逻辑或的关系, 在真实项目中, logic split推荐写成两个规则, 而不是使用 or 分组写到一个规则中.
    rule "infixAnd"
        when
          ( $c1 : Customer ( country=="GB") and  PrivateAccount(owner==$c1))
           or
          ( $c1 : Customer (country=="US") and PrivateAccount(owner==$c1))
        then
            showResult.showText("Person lives in GB or US");
    end
    
    • exists
      exists 是一元分组元素, 用于working memory是否存在符合pattern的fact. 如果有多个fact对象符合pattern, exists 也仅仅会触发一次.
    when 
       //触发一次
       exists Order(qty>1000)
    then
       ...   
    
    when 
       //触发多个
       Order(qty>1000)
    then
       ...   
    
    • not
      not 也是一元分组元素, 用于检查是否存在fact符合pattern, 含义正好和 exists 相反.

    • from
      前面类型匹配的对象都是存在于工作内存中, 但有时候我们需要对非工作内存的对象进行模式匹配, 比如是在global变量中, 比如是在fact的某个属性中, drools 提供了from子句可以支持从这些非工作内存中进行匹配.
      下面示例的 $orderItem 就是从 $order.items 中进行模式匹配.
      效果: 如果只有一个order对象,其他 items 有两个子项, 控制台会输出两行内容.

    package com.sample.rules
     
    import com.sample.Order;
    import com.sample.OrderItem;  
     
    rule "test"
       when 
           $order:Order()
           $orderItem:OrderItem(name =="book") from $order.items  
       then       
           System.out.println($orderItem);  
    end   
    
    • from collect
      上面的from 示例, 最终派生的变量 $orderItem 是单独的对象, 有时候我们需要将派生的变量形成一个集合, 这时就可使用from collect语法.
      下面示例是, 匹配除所有 orderItem 数量>=2 的 order.
      效果:如果只有一个order对象,其他 items 有两个子项, 控制台会输出一行内容
    package com.sample.rules
     
    import com.sample.Order;
    import com.sample.OrderItem; 
    import java.util.List; 
     
    rule "test"
       when 
           $order:Order()
           $items: List(size>=2) from collect (OrderItem() from $order.items)  
       then       
           System.out.println($items.size());  
    end    
    
    • forall
      forall 一般作用于2个或多个pattern, 含义是对于符合pattern1的fact, 要求也必须符合后续其他pattern, 只有这样forall的结果才为true, forall 就是一个加强版的 exists.
      语法:
      forall(
      pattern1
      pattern2
      pattern3
      )
      示例:
    rule "test"
       when       
           forall(
              $order:Order(qty>10)
              OrderItem(order== $order && batchMode=="T" )
             )
       then       
          //$order 变量只能用在forall的后续pattern中, RHS 将无法使用该变量. 
           System.out.println("all order qty>10 is in batch mode");  
    end    
    
    • accumulate
      有时候我们需要对fact先做一些累计统计, 然后基于累计值进行模式匹配, 这时就需用 accumulate 分组元素.
      例子: 需要对最低温度<20并且平均温度>70的sensor reading进行报警处理, 显然这需要先进行 accumulate,
      语法:
    accumulate(
       <source pattern>; 
       <functions> [;<constraints>]    
    )
    

    示例:

    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
    

    LHS 访问对象属性的方法

    LHS访问对象属性可以使用field 名称也可以使用getter方法, 但更推荐直接使用field, 因为它可以利用上 drools 的field indexing, 有更好的性能.

    Person(age>18)  //age 属性
    Person(address.houseNumber==50)  //访问address子对象的属性
    

    list 和 map 的访问

    可以通过下标访问数组/list元素, 可以通过key访问map.
    list示例: Person(childList[0].age==18)
    list示例: Person(childMap["Allen"])

    规则的继承

    新规则继承一个老规则, 继承的仅仅是老规则的LHS部分. 规则继承主要使用场景有: 强化原规则, 或者组合两个规则.

    • 强化规则的示例:
    rule "rule1" 
       when Student(age>10)
       then
          System.out.print("rule1 fired");
    end
    
    rule "rule2"  extends "rule1"
       when Student(age<20)
       then
          System.out.print("rule2 fired");
    end
    
    • 组合两规则的示例
    rule "rule3" 
       when 
          $student:Student(age>10)
       then
          System.out.print("rule3 fired");
    end
    
    rule "rule4"  extends "rule3"
       when 
          $score:Score(student==$student)      
       then
          System.out.print("rule4 fired");
    end
    

    参考

  • 相关阅读:
    VC++中使用ADO方式操作ACCESS数据库
    运维工程师必会的109个Linux命令
    linux上安装配置samba服务器
    ubuntu如何实现访问实际网络中windows共享文件夹
    R语言 入门知识--常用操作和例子
    坚持你选择的路
    scala eclipse plugin 插件安装
    Linux安装卸载Mysql数据库
    Hadoop HA高可用性架构和演进分析(转)
    Spring 系列: Spring 框架简介 -7个部分
  • 原文地址:https://www.cnblogs.com/harrychinese/p/drools_12_lhs.html
Copyright © 2020-2023  润新知