类型判断
// int age
// 查询时条件不分类型,一般直接匹配到自动识别
Person(name=="godme",age==88)
// 类型不对会尝试强制转换,转换成功后继续操作
Person(name=="godme",age=="88")
// 类型强转失败,直接报错
Person(name=="godme",age=="aa")
// 该机制可以规避一些小错误,但是尽量规范,毕竟错误隐蔽
属性连接
// 以下筛选,单独不并列,为了明显显示,没做注释
// 一般逗号分隔,默认 && 连接
Person(name == "godme", male == "male", age < 100)
// 显式声明
Person(name == "godme" && male == "male" && age < 100)
// 自由组合
Person(name == "godme" && male == "male" || age < 100)
Person(name == "godme" || male == "male" && age < 100)
// 分组
Person((name == "godme" && male == "female" || age < 100))
Person(name == "godme" && (male == "male" || age < 100))
// 小问题:
Person(name == "godme",male == "male"|| age < 100) // 成功
Person(name == "godme"||male == "male", age < 100) // 成功
Person(name == "godme"&&male == "male"|| age < 100) // 成功
Person((name == "godme" &&male == "male")|| age < 100) // 成功
Person((name == "godme",male == "male")|| age < 100) // 失败,drl直接提示错误
// 括号分组,内部必须显式声明连接符,不采用括号时,可以局部用连接符直接关联,复用逗号and
// 优先级
// 1. &&
// 2. |
// 3. ,
对象筛选和属性提取
// 属性有两部分功用
// 1. 对象筛选
// 2. 值绑定
// 一般情况:先筛选,再绑定
Person(age > 20, $age:age)
// 筛选时主要看真值,属性可以直接进行复杂运算来计算真值
Person(age * 3 < 180 , $age:age)
// 合一使用,直接绑定,后续真值,名称部分自动绑定对应的属性值,而不是真值结果
Person($age:age<100)
// 另一种类型,非空判断
Person(name != null , $name:name)
// 二合一
Person($name:name!=null)
// 更常用的是属性对象再取值
Person(name="godme", address != null, $city:address.getCity())
// 二合一
Person(name=="godme", $city:address!.getCity())
属性多条件递归
// 一般属性多条件采用枚举方式进行限制
Person(age < 100, age > 0)
// 递归方式
Person(age(<100&&>0)) //Person(age(<100,>0)) 失败,属性递归中必须显式声明连接符
// 复杂一点
// 1. 年龄规范 0<age<100
// 2. 年龄分组 young:10<age<30 old: 60<age<80
Person(age>0 , age < 100 , age >10 && age < 30 || (age <80 && age > 60))
// 简化一点
Person((age>0 && age < 100) && ((age >10 && age < 30) || (age <80 && age > 60)))
// 直接大招
Person(age(>0&&<100)&&((>10&&<30)||(>60&&<80)))
// 熟悉以后,直接写出来就行了
// 有点生疏的话,先规范的分好组,然后"提公因式"就好了
属性分组查询
// 和多条件异曲同工,都是可以"提公因式"
Person(age(>0&&<100)&&((>10&&<30)||(>60&&<80)))
// 属性对象多重筛选
Person(address.city == "China", address.country == "Earth")
// 聚合
Person(address.(city == "China", country== "Earth"))
// 和属性多条件过滤差不多,需要注意的就是属性调用的".", 还可以加上非空
Person(address != null, address.city == "China", address.country == "Earth")
Person(address!.(city == "China", country== "Earth"))
日期字符化
// 一般判断时间都是通过毫秒值进行判断
// 即使是其他判断方式也是基于此
// 只是用起来的确不够方便,也不够直观
Person(birth.getTime() > new Date().getTime())
// 时间字符化
// 通过设置drools本身默认的时间格式 drools.dateformat,就可以直接用格式化字符串表示时间了
// System.setProperty("drools.dateformat", "yyyy-MM-dd")
Person(bitrh == "2018-Dec-23")
集合
// 对于drl中集合类型的操作,java中的操作的确可以沿用
// 1. 方法调用
list(index).getAge() == 18
map.get(name).isValid()
// 这种办法,基本都是对"对象"的接口("方法")调用
// 2. 属性调用
// drl中也可以直接进行属性调用
list[index].age == 18
map[name].valid
// 都是[]数组形式的直接调用
// 说起来,对象之中也能够发现这种现象
// 属性
Person(name == "godme")
// 方法
Person(getName() == "godme")
子类型判断
// 对于复合类型而言,需要区别对待
// 这种复合一般针对继承而言
// 用一个顶层父类进行接收,最终需要追溯到最底层,就要进行类型的判断了
Person(address != null, address instanceof Location , $city:address.city)
// instance 就是追溯类别,进行类型判断
// 有时候还需要进行强转操作
// 对象也可以进行全路径的指定,带全名称空间(包名)而已,就不多讨论了
Person(address != null, address instanceof Location , $city:address#Location.city)
// 层级强转 + 关注对象变换 + 判断
Person(address != null, address#Location.city#DetailCity.population > 1000)
// +非空
Person(address != null, address#Location!.city#DetailCity!.population > 1000)
Person(address!#Location!.city#DetailCity!.population > 1000)
// 猜测, 未实践,不知道强转前能不能进行非空的融合判断
// 疑问
//#这不是注释么,后续的好像都注释掉了,我这个实验不太成功
// 不过官方文档好像是这样,先就这样吧
位置参数
drl
package com.sample;
// 声明类
declare Person
name:String
age:int
male:String
end
rule "attr_filter"
when
//平时筛选都需要指定参数名称和参数值
Person(name == "godme", age == 45, male == "male") // 可以简便一点么
// 和方法调用一个样,只要记住了属性的声明顺序,也是可以"对号入座"的
// 声明看上方
// 上一句也可以写作
Person("godme",45,"male";)
// 这个叫做位置参数,也就是对号入座
// 严格区分筛选的条件填写部分,可以分作两部分
// 1. 位置参数
// 2. 条件参数
// 中间用分号";"进行就行,前面是位置参数,后面是条件参数
// 重要
// 0. 分隔
// 分号别忘记,也别用错
// 1. 顺序
// 从上一句能看出来,填写的顺序是按照声明顺序来的,记不住就大发了
// 2. 默认
// 当对号入座发现属性有值,就开始筛选,如果没有属性值的话,就会把设置的"筛选值"当做"默认值"置入对象
// 3. 指定
// 位置参数虽然都是"对号入座",不过也是可以进行指定的
Person(age==88) // 这个看不出来,需要综合一下
$p:Person(age=="45";name == "godme") // 可能觉得神经病,但是这的确是没问题
// Person(age==45;name == "godme") // 直接上数字会报错,只能幸好我会"强转"
// 其他
Person("godme";) // 单独位置参数也必须有分号";", 默认的是条件参数
// 全部亲测, 放心食用, 只是都是单条用,为了明显点才没注释
then
System.out.println($p);
end
java
public static final void main(String[] args) {
try {
KnowledgeBase kbase = readKnowledgeBase();
StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession();
KnowledgeRuntimeLogger logger = KnowledgeRuntimeLoggerFactory.newFileLogger(ksession, "test");
FactType personClasee = kbase.getFactType("com.sample", "Person");
Object person = personClasee.newInstance();
HashMap<String, Object> attrs = new HashMap<>();
attrs.put("name", "godme");
attrs.put("age", 45);
attrs.put("male", "male");
personClasee.setFromMap(person, attrs);
ksession.insert(person);
ksession.fireAllRules();
logger.close();
} catch (Throwable t) {
t.printStackTrace();
}
}
字符串检测
// 字符串检测
// 发音检测(这特么都有)
// 中文没试
Person( name soundslike "foobar") // fubar 能匹配
// 开头
Person(name str[startsWith] "g")
// 结尾
Person(name str[endWith] "me")
// 长度检测
Person(name str[length] 5)
多选
// 其中
Person(name in ("godme", "judas"))
// 不再其中
Person(name not in ("godme", "judas"))
真值计算
// 简单的真值判断执行,返回真值
eval(2 > 3)
// 常用
eval(true)
eval(false)
笛卡尔积
// 多对象的查询,和SQL查询办法类似,会产生笛卡尔积
$man:Person($man_age:age, male == "male")
$woman:Person($woman_age:age, male == "female")
eval($man_age - $woman_age == 2)
// 结果返回的是男比女年龄大两岁的遍历组合
// 查询过程中会产生笛卡尔积,然后通过其他语句控制输出
// 笛卡尔积,简单理解就是元素的组合遍历,具体可以自行"想象"(学习)-----(西游筋?唐山葬?)