3 Drools 规则引擎实战

770 阅读7分钟

3.0 概述

本章将详细介绍如何使用Drools规则引擎进行规则开发。介绍如何使用Drools语法编写规则,以及如何让规则生效,以及如何借助Drools属性如何让规则更具有灵活性。

3.1 基本使用方法

基本使用方法是Drools规则引擎应用的最基础内容,主要介绍如何使用Drools规则引擎进行规则匹配,并进行规则执行。在这一章节中,我们将介绍如何使用Drools规则引擎进行匹配,如何创建规则,以及如何加载和执行规则。

package com.example.rules;

import com.example.domain.Person;
import org.kie.api.KieServices;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;

public class BasicUseExample {

    public static void main(String[] args) {
        KieServices kieServices = KieServices.Factory.get();
        KieContainer kieContainer = kieServices.newKieClasspathContainer();
        KieSession kieSession = kieContainer.newKieSession("basicUseExample");

        Person person = new Person();
        person.setAge(18);
        kieSession.insert(person);
        kieSession.fireAllRules();

        kieSession.dispose();
    }
}

3.2 方法调用

在Drools规则引擎中,您可以在规则条件或动作中调用方法。在这一章节中,我们将介绍如何使用方法调用语法,并介绍如何使用Drools规则引擎中的内置方法,以及如何在Drools规则引擎中自定义方法。

rule "method call rule"
when
  $person: Person(age > 18)
then
  $person.setAdult(true);
end

在上面的代码片段中,我们创建了一个名为method call rule的规则,当在Working Memory中存在一个Person对象的age属性值大于18时,执行语句会调用该Person对象的setAdult方法,将其adult属性设置为true。

方法调用不仅仅是可以用于设置对象属性,它还可以用于调用其他任意的Java方法,以实现复杂的业务逻辑,如下所示:

rule "method call rule with external method"
when
  $person: Person(age > 18)
then
  externalMethod($person);
end

private void externalMethod(Person person) {
  // do something here
}

在上面的代码片段中,我们在规则中调用了一个外部方法,该方法可以对Person对象进行处理,从而实现复杂的业务逻辑。

通过方法调用,Drools可以与Java代码紧密结合,使得规则的功能更加强大,能够满足更加复杂的业务需求。

3.3 关系语法

在Drools中,我们可以通过关系语法来定义复杂的关系,并与模式匹配语法配合使用,从而实现复杂的规则逻辑。

例如:定义Person类,有属性name和age,如果某个Person的年龄大于18,那么他就是成年人。

rule "Adult"
when
	$person:Person(age > 18)
then
	System.out.println($person.getName() + " is an adult.");
end

以上代码是一个简单的关系语法的例子,通过关系语法,我们定义了一个规则,当某个Person的年龄大于18时,打印这个Person是成年人。

关系语法还支持更复杂的比较运算,如果某个Person的年龄大于18并且小于30,那么他就是青年人。

rule "Young people"
when
	$person:Person(age > 18 && age < 30)
then
	System.out.println($person.getName() + " is a young people.");
end

以上代码演示了如何使用关系语法进行多条件判断,更详细的关系语法可以参考文章

此处为语雀内容卡片,点击链接查看:www.yuque.com/xiangdong-m…

3.4 动态规则

动态规则是指在规则执行过程中可以动态地添加,修改或删除规则。这是一种非常有用的特性,因为它允许我们在运行时更改规则,从而使得应用程序更加灵活和可配置。

在Drools中,我们可以使用KieSession的insert方法动态地添加规则,使用update方法动态地修改规则,使用retract方法动态地删除规则。

代码演示:

例如,我们要实现一个动态规则,每当一个人购买了100元或以上的商品时,都要给他发送一封礼券。

// 定义规则
rule "Send Coupon for 100 RMB Purchase"
when
  $person : Person(purchasedAmount >= 100)
then
  System.out.println("Send coupon to " + $person.getName());
end

我们可以在代码中动态地添加这个规则:

KieSession kieSession = kieContainer.newKieSession();

// 动态添加规则
kieSession.insert(new RuleImpl("Send Coupon for 100 RMB Purchase", 
  new ArrayList<>(), "System.out.println("Send coupon to " + $person.getName());", 
  ResourceType.DRL));

// 插入一个Person对象
Person p = new Person("John", 150);
kieSession.insert(p);

// 执行规则
kieSession.fireAllRules();

同样的,我们也可以动态地删除这个规则:

// 动态删除规则
kieSession.delete(kieSession.getAgenda().getRule("Send Coupon for 100 RMB Purchase"));

3.5 管理规则

在Drools中,管理规则是指如何维护规则的生命周期。这包括了规则的定义,加载,执行和移除。管理规则有助于确保规则引擎可以正常运行,并且可以根据需要动态地更新规则。

在Drools 7.10.0 Final版本中,Drools推荐使用KieBase作为管理规则的核心。KieBase管理了所有的规则、流程和评估。它可以被看作一个规则引擎实例,而不是一个规则集合。

下面是一个示例代码,用于加载和执行规则。在此代码中,我们使用Drools 7.10.0 Final版本。

KieServices ks = KieServices.Factory.get();
KieContainer kc = ks.getKieClasspathContainer();
KieBase kbase = kc.getKieBase("kbase1");
KieSession ksession = kbase.newKieSession();

KieBase是可以动态更新的,可以根据需要加载、卸载规则。KieSession管理了所有的规则匹配和执行。每个KieSession都是独立的,拥有自己的状态和记忆。可以在多个线程中共享KieBase,但不能共享KieSession。

3.6 逻辑语法

逻辑语法是Drools中非常重要的一部分,它可以用来定义规则的逻辑关系。逻辑语法包括了 and、or、not 等运算符,可以用来定义规则的逻辑关系。

示例代码:

rule "example rule"
when
    $person : Person( name == "John" )
    or
    $person : Person( age == 30 )
then
    System.out.println("Hello " + $person.getName());
end

在上面的代码中,逻辑语法中的 or 运算符表示如果匹配到名字为 John 的 Person 对象,或者匹配到年龄为 30 的 Person 对象,就执行规则。

3.7 规则优先级和执行顺序

规则优先级是指规则的执行先后顺序,Drools 通过规则的 salience 属性来定义规则的优先级。Salience 属性的数值越大,规则的执行优先级越高,规则触发时先触发优先级高的规则。

如下代码演示了如何通过设置 salience 属性来控制规则执行顺序:

rule "rule 1"
salience 10
when
$c : Customer(age < 30)
then
// do something
   end

rule "rule 2"
salience 5
when
$c : Customer(age >= 30)
then
// do something
   end

可以看到,在以上代码中,rule 1 的 salience 属性为 10,rule 2 的 salience 属性为 5,因此 rule 1 会在 rule 2 之前执行。

除了 salience 属性,还可以通过创建 KieSession 时传入的构造器参数来设置规则的执行顺序。

3.8 规则组合

规则组合是指在 Drools 规则引擎中,对多条规则进行组合,以实现更加复杂的业务逻辑。Drools 提供了多种规则组合方式,比如使用 "from" 和 "accumulate" 关键字,使用 "collect" 函数,使用 "group by" 关键字等。下面是一个使用 "from" 和 "accumulate" 关键字的代码示例:

rule "calculate total score"
when
  $student : Student( name == "Tom" )
  accumulate( $score : Score( student == $student ), 
              $totalScore : sum( $score.score ) )
then
  System.out.println( "The total score of student Tom is " + $totalScore );
end

在上面的代码中,我们使用了 "accumulate" 关键字,从 "Score" 对象中找到与当前 "Student" 对象关联的所有 "Score" 对象,并将其分数求和,最后在 "then" 部分输出总分。

此外,Drools 还提供了 "collect" 函数,允许我们通过指定的条件,从一组对象中收集符合条件的对象。下面是一个使用 "collect" 函数的代码示例:

rule "Collect function example"
when
    $list : ArrayList()
    $count : Integer() from collect( String( this == "hello" ) )
then
    System.out.println("Hello count : " + $count );
end

在这个例子中,我们使用了 "collect" 函数来统计列表中 "hello" 字符串的个数。使用 "collect" 函数可以帮助我们更方便地统计数据。

使用 "group by" 关键字可以对匹配到的对象进行分组,从而方便对分组后的结果进行更深入的分析。示例代码:

rule "group by example"
when
    $g : Group( ) from collect( Person( age > 18 ) )
then
    // 对分组后的结果进行操作
end

在上面的代码示例中,使用了 "group by" 关键字对年龄大于 18 的 Person 对象进行分组,然后对分组后的结果进行操作。

3.9 规则分组

Drools中的规则分组是将相关的规则组合在一起,并对它们进行分组,以便于更好地管理和执行。它是通过在规则上使用 "agenda-group" 属性来实现的,该属性允许指定规则所属的分组。在代码中,通过如下代码来指定规则分组:

rule "rule1"
    salience 10
    agenda-group "group1"
when
    ...
then
    ...
end

rule "rule2"
    salience 20
    agenda-group "group2"
when
    ...
then
    ...
end

在这里,我们有两个规则,分别命名为 "rule1" 和 "rule2",并分别属于 "group1" 和 "group2" 这两个规则组。在执行规则时,可以通过如下代码来指定要执行的分组:

ksession.getAgenda().getAgendaGroup("group1").setFocus();
ksession.fireAllRules();

通过这种方式,可以灵活地控制规则的执行顺序和分组,使其更具适用性和灵活性。

3.10 规则管理系统

在 Drools 规则引擎中,规则管理系统是一个重要的组成部分,它可以帮助我们组织和管理规则。规则管理系统包括了以下几个核心概念:

    • KnowledgeBase(知识库):保存着规则的集合。
    • KnowledgeSession(知识会话):与知识库交互的环境,可以在知识会话中执行规则。
    • KnowledgeBuilder(知识构建器):用于构建知识库的工具。
    • KnowledgePackage(知识包):保存着一组规则的集合。

以下是使用 Drools 7.10.0 Final 版本创建规则管理系统的代码示例:

KieServices kieServices = KieServices.Factory.get();
KieFileSystem kfs = kieServices.newKieFileSystem();
kfs.write("src/main/resources/rules/rules.drl", releString);
KieBuilder kieBuilder = kieServices.newKieBuilder(kfs).buildAll();
KieModule kieModule = kieBuilder.getKieModule();
KieContainer kieContainer = kieServices.newKieContainer(kieModule.getReleaseId());
KieBase kieBase = kieContainer.getKieBase();

在此例中,我们通过KieServices工厂类获取KieServices实例,然后通过它来实例化KieFileSystem。之后,我们通过KieFileSystem写入规则文件,并通过KieBuilder来构建所有规则。随后,我们通过KieBuilder获取KieModule,再通过KieModule获取KieContainer。最后,我们通过KieContainer获取KieBase,以便在应用程序中使用。

3.11 规则冲突处理

在Drools规则引擎中,当多个规则对同一个事实进行决策时,可能会发生冲突。例如,两个规则同时都推荐了一个产品,但是它们的价格和评级不同。在这种情况下,需要定义一种机制来解决冲突,Drools 提供了多种冲突处理策略,比如说:默认冲突处理策略,用户定义的冲突处理策略,优先级高的规则冲突处理策略等。

Drools规则引擎提供了以下三种冲突处理方法:

    • 优先级:每个规则有一个优先级,当多个规则对同一个事实决策时,优先级高的规则会覆盖优先级低的规则。
    • 时间戳:当规则被激活时,会记录当前的时间戳。当冲突发生时,时间戳更新的规则会覆盖时间戳不更新的规则。
    • 权重:每个规则有一个权重,当多个规则对同一个事实决策时,权重更高的规则会覆盖权重更低的规则。