当前位置: 首页 > 后端技术 > Java

条件在流口水when

时间:2023-04-01 13:50:18 Java

1。前言本文主要记录drools中的模式和约束以及when中conditions的写法。2.语法结构3.模式示例3.1单对象匹配规则"只要工作内存中有Person对象,就会执行,有多次执行"whenPerson()thenSystem.out.println("工作内存中有一个Person对象");end3.2匹配任意对象规则"只要工作内存中有一个对象,就匹配"当Object()thenSystem.out.println("As只要工作内存中有对象,就会被匹配");end3.3with条件匹配规则"匹配年龄小于20岁"whenPerson(age<20)//Etc.getAge()<20,建议使用属性写法thenSystem.out.println("Matchagelessthan20yearsold");end3.3.1注意事项1、匹配条件的结果必须为真或假。2.Person(age<20)和Person(getAge()<20)是等价的,但是推荐第一种方法。3.Person(age<20)默认会调用getAge()方法。如果该方法不存在,它将调用age()方法。如果不存在,将抛出异常。4、Drools引擎在调用的时候会缓存匹配的结果来提高效率,所以我们的getter方法不要有状态。3.4嵌套属性匹配3.4.1访问单个嵌套属性规则"Accesstonestedattributes"whenPerson(car.name=="BMW")thenSystem.out.println("Accesstonestedattributes");end3.4.2访问多个嵌套属性规则"Nestedattributeaccess-02"whenPerson(age<20&&car.name=="BMW"&&car.color==null)thenSystem.out.println("访问嵌套属性-02");end3.4.3属性分组。()将这些属性访问器分组到嵌套对象中以获得更具可读性的规则规则“访问嵌套属性-03”whenPerson(age<20,car.(name=="BMW"||color!=null))//属性组访问然后System.out.println("Nestedattributeaccess-03");end3.4.4强制类型转换在嵌套模式中,我们可以使用#语法转换为子类型,并使超类型的getter为子类型工作。rule"访问嵌套属性-强制类型转换"whenPerson(age<20,car#BMWCar.name=="BMW")//强制类型转换thenSystem.out.println("访问嵌套属性-强制类型转换");end注意上面的car#BMWCar,这里是将car转换成BMWCar类型使用。3.4.5注意事项在有状态的kie会话中,需要谨慎使用嵌套属性。因为Drools引擎的工作内存不知道任何嵌套值,也不会检测它们何时发生变化。3.5Calljavamethodconstraintrule"Calljavamethodconstraint"whenPerson(!isChild())thenSystem.out.println("Calljavamethodconstraint");end3.5.1注意实现isChild()方法不要修改事实上,因为drools引擎会缓存调用过程中的结果,以提高工作效率。如果状态被修改,匹配结果可能不准确。3.6多字段约束规则"Multiplefieldconstraints"whenPerson((name!=null&&age<20)&&car!=null)//isChild方法中需要状态改变thenSystem.out.println("Multiplefieldconstraints");end3.7顶层字段约束Person(name!=null,age<20,car!=null)Person((name!=null&&age<20)&&car!=null)以上两种方式写是一样的。3.7.1注意事项1.在顶级字段约束中,性能高于&&。2.&&优先于||,并且&&和||都是取得优先权。3.不要把,嵌入到复合表达式中,比如:Person((name!=null,age<20),car!=null)这种写法是错误的,需要把,换成&&符号。3.8日期类型的使用drools中默认的日期格式是dd-mmm-yyyy,这里我们通过设置系统变量drools.dateformat修改为yyyy-MM-ddHH:mm:ss格式。rule"Useofdatetype"when$p:Person(registerDate<'2022-05-2412:12:12')//日期格式比较,System.setProperty("drools.dateformat","yyyy-MM-ddHH:mm:ss");thenSystem.err.println("日期类型的注册时间:"+newSimpleDateFormat("yyyy-MM-ddHH:mm:ss").format($p.getRegisterDate()));end4.在模式和约束规则中使用绑定变量当$p:Person($age:age)thenSystem.err.println("Usebindvariables"+$p.getName()+":"+$age);我们可以在end的后期使用$p和$age。$p表示当前规则运行时工作内存中匹配的Person对象,$age表示匹配到该对象的年龄属性。绑定变量一般以$开头,以区别于fact的属性。4.1字段约束规则中绑定变量的写法“使用绑定变量——写法不好”whenPerson($age:age*2<100)thenSystem.err.println(“使用绑定变量——不好的写法”+":"+$年龄);end不明确,执行效率不高。4.2在字段约束规则中写绑定变量的好方法《使用绑定变量——推荐的写法》whenPerson(age*2<100,$age:age)//这样比System.err.println更清晰高效("使用绑定变量-推荐写法"+":"+$age);end4.3约束绑定只考虑第一个原子表达式Person($age1:(age*2))andTheresultofPerson($age2:age*2)不同,$age1的结果是$age2的两倍。5.支持的运算符5.1.()分组属性使用.()运算符将属性访问器分组到嵌套对象中Person(age<20,car.(name=="BMW",color==null))Person(age<20,car.name=="BMW",car.color==null)以上两种写法意义相同5.2#类型转换在嵌套模式下,我们可以使用#语法Cast为子类型并使超类型的getter可用于子类型。Person(car#BMWCar.brand=="BMW")car#BMWCar指的是将car转换为BMWCar类型。5.3!NestedattributesarenullsafePerson(car!.name=="BMW")//如果此时car为null,使用car!.name不会报错。当我们的属性嵌套时,使用!。以避免空指针异常。5.4[]List或Map1的操作,List操作-通过索引访问Person(hobbyList[0]=="playingbasketball")2、map操作-通过key操作Person(map["key1"]=="value1")Person(map["key1"]=="value1")这个map是Person的一个字段是map5.5<,<=,>,>=,==,!=,&&,||这些运算符和Java中的用法是一致的。<,<=,>,>=这些操作符,如果用在Date类型的字段中,<表示之前,对于String类型的字段,排序比较Person(age((>30&&<40)||(>=18&&<=25))&&car!=null&®isterDate<'2022-12-1212:12:12')Person(age>=18&&age<=25)andPerson(age(>=18&&<=25))是等价的。5.6匹配,不匹配正则匹配用于判断给定字段是否与执行的正则表达式匹配。正则表达式可以是给定的字符串,也可以从变量中动态获取。转义需要使用\\。Person(namematcheshobbyList[2]&&car.namenotmatches"^Audi")//正则表达式可以是动态的5.7contains,notcontainscollectionorstringcontainswhatcontains:contains;不包含:不包含。1.验证Array或Collection是否包含指定字段的值(可以是常量或变量)。2、也可以是String类型的字段是否包含某个值(可以是常量也可以是变量)。Person(hobbyList包含“打篮球”&&hobbyList不包含“打橄榄球”&&.hobbyList不包含name&&name包含“Zhang”&&name不包含car.name)hobbyList:List类型的字段。name或car.name:String类型字段。从上面的例子可以看出:hobbyListcontains"playingbasketball":"playingbasketball"是一个常量字符串。hobbyList不包含nam:“name”是一个动态变量,从Person获得。为了向后兼容,excludes运算符的工作方式与不包含相同。5.8memberOf,而不是memberOf字段是否是集合的成员验证一个字段是否是Array或Collection的成员。Array或Collection必须是可变的。Person("playingbasketball"memberOfhobbyList&&"basketball"notmemberOfhobbyList&&namenotmemberOfhobbyList)5.9str验证字段是以what开头还是以what结尾来验证指定的字符串是否以str[startsWith]开头。验证指定的字符串是否以str[endsWith]结尾。验证指定字符串的长度str[length]。看看这个类org.drools.core.base.evaluators.StrEvaluatorDefinitionPerson(namestr[startsWith]"Zhang"&&namestr[endsWith]"Three"&&namestr[length]2&&"ZhangSan"str[startsWith]"张")5.10innotin判断一个值是否在某组值中Person($name:name&&namein($name,"李四")&&"playingbasketball"in("playingbasketball","playingfootball")&&car.namenotin("playingbasketball",$name))6.算子的优先级下表从高到低列出了DRL算子的优先级。运算符类型OperatorsNotes嵌套或空安全属性访问。,.(),!.NotstandardJavasemanticsListorMapaccess[]NotstandardJavasemanticsConstraintbinding:NotstandardJavasemanticsMultiplicative*,/%Additive+,-Shift>>,>>>,<,>=,instanceofEquality==!=Usesequals()and!equals()semantics,notstandardJavasameandnotsamesemanticsNon-short-circuitingAND&Non-short-circuitingexclusiveOR^非短路包含OR`\`逻辑AND&&逻辑OR`\`三元?:Comma-separatedAND,不是标准的Java语义7,DRL支持规则和条件元素(关键字)DRL支持更多的规则和条件元素,这里解释一些关键字的用法。7.1and使用and将条件分组为逻辑组合。并支持中缀和前缀方法。可以使用()明确地完成分组。默认是and//规则and-01and-02and-03意义相同,Person和Order对象都需要存在于工作内存规则"and-01"当Person()和Order()thenSystem.out.println("and-01");endrule"and-02"when(andPerson()Order())thenSystem.out.println("and-02");endrule"and-03"当Person()Order()然后System.out.println("and-03");end7.2oror也支持多种写法,这里列出一种写法。与java规则"or-01"中的or用法一致when$p:Person()orOrder()//只要内存中有Person或Order对象,规则就会执行。如果两者都存在,则可能会执行多次。如果只想执行一次,可以看看existsthen的用法System.out.println("or-01");end7.3存在匹配工作内存中的Fact,只会在第一次匹配时触发,不会触发多次,如果与多种模式一起使用,需要使用()。简单理解:假设我一次插入5个Person对象到workingmemory中,如果existsmatches,只会执行一次,不会执行5次。rule"exists"whenexists(Person()orOrder())//single:existsPerson()multiple:need()splitthenSystem.out.println("existsmultiplePerson()对象存在于工作内存中同时和Order()对象,规则只执行一次");end7.4not当这个对象在规则的内存中不存在时,触发规则。例如:notPerson()表示当规则内存中没有名为Person的Fact对象时触发。rule"not-02"whennot(Person(name=="李四")orOrder(orderId==1000))thenSystem.out.println("not-02,Person#name==doesnotexistintherulememory当李四或Order#orderId=1000"时触发");end7.5from用它来指定模式的数据源。这使Drools引擎能够对不在工作内存中的数据进行推理。数据源可以是绑定变量的子字段或方法调用的结果。用于定义对象源的表达式是遵循正常MVEL语法的任何表达式。因此,from元素使您能够轻松地使用对象属性进行导航、执行方法调用以及访问映射和集合元素。基本用法:rule"from"when$p:Person($hobbyList:hobbyList)$hobby:String()from$hobbyListthenSystem.out.println("如果有多个$hobby,那么这个可能会执行多次");System.out.println("from:person:"+$p.getName()+"hobbyis:"+$hobby);插入kie会话以提高性能。与lock-on-active一起使用的解决方案使用fromwithlock-on-active规则属性会导致规则不被执行。您可以通过以下方式之一解决此问题:当您可以将所有事实插入Drools引擎的工作内存或在约束表达式中使用嵌套对象引用时,请避免使用from元素。将modify()中使用的变量放置在阻止作为规则条件中的最后一句话。当您可以明确管理同一规则流组中的规则如何将激活相互放置时,请避免使用锁定活动规则属性。后跟模式解决方案的form子句包含from子句的模式后不能跟另一个以圆括号开头的模式。此限制的原因是DRL解析器将from表达式读取为“from$l(String()orNumber())”,这无法将此表达式与函数调用区分开来。最简单的解决方案是将from子句括在圆括号中,如下例所示://Donotuse`from`inthisway:ruleRwhen$l:List()String()from$l(String()orNumber())then//Actionsend//以这种方式使用`from`代替:规则Rwhen$l:List()(String()from$l)(String()orNumber())then//Actionsend7.6入口点使用它来定义对应于模式数据源的入口点或事件流。此元素通常与from条件元素一起使用。您可以为事件声明入口点,以便Drools引擎仅使用来自该入口点的数据来评估规则。您可以通过在DRL规则中引用它来隐式声明入口点,或者在您的Java应用程序中显式声明入口点。drlfilerule"entry-point"when$o:Order()fromentry-point"order-entry-point"//这个地方的数据来自order-entry-point,kieSession.getEntryPoint("order-entry-观点”);$p:Person()//这里的数据来自kieSession.insertthenSystem.err.println("entry-point"+$p.getName()+":"+$o.getOrderId());endOrder()可以从上面的规则文件中获取,Order()对象来自order-entry-point。而不是来自其他地方。java文件//order-entry-point这是drl文件中定义的EntryPointentryPoint=kieSession.getEntryPoint("order-entry-point");entryPoint.insert(newOrder(2001L,10000L));8、完成项目https://gitee.com/huan1993/spring-cloud-parent/tree/master/drools/drools-drl-when9,参考地址1,https://docs.drools.org/7.69.0。最终/流口水文档/html_single/index.html#drl-rules-WHEN-con_drl-rules