drools7规则引擎——动态加载规则

贴个Drools 7.15.0官方文档地址:https://docs.jboss.org/drools/release/7.15.0.Final/drools-docs/html_single/index.html

这个链接可以下载PDF版本的文档:http://www.drools.org/learn/documentation.html

规则引擎在IoT的数据过滤,保险业务系统,积分系统等很多场景都应用广泛。使用规则引擎最大的好处是可以将规则与业务代码分离,动态增加和删除规则,可以做到很友好的提供给业务操作人员去编辑具体的业务规则,而非技术开发人员。drools作为开源项目中比较知名的规则引擎之一,想必会有很多人想使用它来应对逐渐复杂的业务规则。下面我们介绍怎样通过drools实现动态的规则管理。

首先在自己工程中引入drools依赖包,pom.xml如下配置:

		
		
			org.drools
			drools-core
			7.2.0.Final
		
		
			org.drools
			drools-compiler
			7.2.0.Final
		
		
			org.kie
			kie-api
			7.2.0.Final
		
		
			org.kie
			kie-internal
			7.2.0.Final
		

接下来,引用官方示例,直接上代码,

String rule = "import com.demo.drools.Cheese;\r\n" + 
		              "import com.demo.drools.Person;\r\n" + 
				      "rule \"规则\"\r\n"+
				      "when\r\n" + 
				      "    Cheese( $cheese : name == \"cheddar\" )\r\n"+ 
				      "    $person : Person( favouriteCheese == $cheese )\r\n" + 
				      "then\r\n"+ 
				      "    System.out.println( $person.getName() + \" likes cheddar\" );\r\n" + "end\r\n" + "	";
		KnowledgeBuilder builder = KnowledgeBuilderFactory.newKnowledgeBuilder();
                //以DRL形式加载规则
		builder.add(ResourceFactory.newByteArrayResource(rule.getBytes()), ResourceType.DRL);
		KnowledgeBuilderErrors errors = builder.getErrors();
		for (KnowledgeBuilderError error : errors) {
			System.out.println(error.getMessage());
		}
		InternalKnowledgeBase kBase = KnowledgeBaseFactory.newKnowledgeBase();
		kBase.addPackages(builder.getKnowledgePackages());
                //获取规则引擎会话session
		KieSession session = kBase.newKieSession();
		Person person1 = new Person("张三", "cheddar");
		Person person2 = new Person("李四", "dicars");
		Cheese cheese1 = new Cheese("cheddar");
		Cheese cheese2 = new Cheese("dicars");
                //插入需匹配的对象
		session.insert(person1);
		session.insert(person2);
		session.insert(cheese1);
		session.insert(cheese2);
               //执行规则
		session.fireAllRules();
               //释放资源
		session.dispose();
public class Person {
	private String favouriteCheese;
	private String name;
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public Person(String name, String favourite) {
		favouriteCheese = favourite;
		this.name = name;
	}
	public String getFavouriteCheese() {
		return favouriteCheese;
	}
	public void setFavouriteCheese(String favouriteCheese) {
		this.favouriteCheese = favouriteCheese;
	}
}
/*****************************************************************/
public class Cheese {
	private String name;
	public Cheese(String name) {
		this.name = name;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
}

示例中的规则是以DRL文件形式加载的,所以我们可以自己生成合法的DRL文本,然后初始化规则引擎实例。Drools支持多种不同的规则表达形式,例如决策表,properties文件,DSL语言,java语言,XML等十几种形式,同时支持多种规则加载方式,例如字节流,文件,I/O流,URL,String等。所以,想实现动态加载规则的方法有很多,感兴趣的话可以自己去尝试其他的方法。初始化规则引擎之后,内部会按照Rete算法生成匹配网络,然后我们就可以向里面insert需要匹配的对象,添加完对象后,显示调用session.fireAllRules()方法让规则引擎工作,最后符合条件的对象会执行规则的动作。

官方推荐使用DSL(Domain Specified Language)领域专用语言书写规则,领域专家可以通过简单的编程方式描述领域中的所有活动和规则。下面介绍上面例子中用DSL语言书写的规则:

rule "规则"
when
    Cheese( $cheese : name == "cheddar" )
    $person : Person( favouriteCheese == $cheese )
then
    System.out.println( $person.getName() + " likes cheddar" );
end

上面这条规则表示:“最喜欢奶酪品牌是'cheddar'的人的姓名有哪些”。这条规则包含了条件(when)和动作(then),条件是用DSL语言书写,动作可以用java语言书写。规则实际上包含了3个条件,分别是

  1. 规则引擎中是Cheese的对象
  2. 规则引擎中是Person的对象
  3. 这些Person对象中favouriteCheese='cheddar'

只有满足以上条件的对象才能被执行动作(then)部分。DSL语言中还有非常多的关键字可以使用,比如循环的执行规则,定时执行规则等等操作,下面这个链接详细的解释了DSL可以使用的一些关键字和函数,可以很方便的完成一些操作。

https://docs.jboss.org/drools/release/7.15.0.Final/drools-docs/html_single/index.html#_droolslanguagereferencechapter

上面实现了动态加载规则,并且成功执行结果,那么接下来我们可以让规则的编写简单化。对于业务人员来说,最好的方式是使用自然语言书写规则。那么我们需要做的就是把自然语言编写的规则转换为DSL语言。仍然以上面的规则为例,“最喜欢奶酪品牌是'cheddar'的人的姓名有哪些”。业务人员只需要输入:

条件:人.喜欢的奶酪名='cheddar'

动作:输出->人.姓名

我们将这句话一一转换为DSL对应的语言。首先是对象的转换:人->Person,奶酪->Cheese;属性的转换:奶酪名->Cheese.name,姓名->Person.name,喜欢的奶酪名->Person.favouriteCheese ;动作的转换:输出->System.out.println();逻辑运算符的转换:"="->"==",对象的引用约定为:$对象名,因此人和奶酪的对象引用转换为:$person,$cheese;'('、')'和""引号、括号等符号作为语义补充,所以得到转换后的部分DSL为:

//条件语句  
Cheese( $cheese : name == "cheddar" )
$person : Person( favouriteCheese == $cheese )
//动作语句
System.out.println( $person.getName() + " likes cheddar" )

再将上面的代码片段组合成标准的DSL格式:

rule "规则"
when
    //条件语句  
    Cheese( $cheese : name == "cheddar" )
    $person : Person( favouriteCheese == $cheese )
then
    //动作语句
    System.out.println( $person.getName() + " likes cheddar" )
end

那么一个简单的自然语言的规则就转换为一个标准的DSL语句。当然更复杂的语句也基本类似,无非是对更多的运算符,关键字等分别做转换。对语言的处理继续深入的话其实非常的丰富和具有挑战性。

        后续我会继续分享怎样将SQL语句转换为DSL语言。SQL作为模式匹配语言中的一种,在条件过滤和数据筛选方面非常灵活,那么后面我们将分享怎样让SQL语句运行在Drools规则引擎之上。

你可能感兴趣的:(智能IoT系统,Drools,SQL,动态规则)