使用规则引擎 Drools 替代各种if-else

学习Drools,我们可以通过一个简单的案例来了解该规则引擎的使用过程。以下是一个样例工程的步骤:

  • 首先,我们需要创建一个 Maven 工程。在 pom.xml 文件中添加 Drools 的依赖:

<dependency>
    <groupId>org.drools</groupId>
    <artifactId>drools-core</artifactId>
    <version>7.54.0.Final</version>
</dependency>
  • 接着,我们创建一个规则文件,例如 rules.drl:
import org.drools.example.model.Person;

rule "over 18"
    when
        p : Person(age > 18)
    then
        System.out.println(p.getName() + " is over 18!");
end


在这个规则中,我们定义了一个名为 over 18 的规则,它将会匹配 age 大于 18 的 Person 对象;当匹配成功时,规则引擎会输出此人已经成年。

  • 我们还需要创建一个数据模型 Person.java,用于存储人员信息:


public class Person {
    private String name;
    private int age;
    // ... getter and setter
}
  • 最后,我们创建一个测试类来加载规则文件并应用规则:

public class DroolsTest {

    public static void main(String[] args) {
        KieServices kServices = KieServices.Factory.get();
        KieContainer kContainer = kServices.getKieClasspathContainer();
        KieSession kSession = kContainer.newKieSession();

        Person jack = new Person("Jack", 20);
        Person mary = new Person("Mary", 17);

        kSession.insert(jack);
        kSession.insert(mary);
        kSession.fireAllRules();
        kSession.dispose();
    }

}

我们首先创建了一个 KieSession 对象,它用来加载规则,并定义了两个 Person 对象,然后将这两个对象插入到 KieSession 中,执行 fireAllRules() 方法来匹配规则,并输出 Jack 已经成年。

以上是一个简单的 Drools 学习案例,其基本过程是:定义规则文件 -> 创建数据模型 -> 创建 KieSession -> 插入数据,触发规则。

  • Drools 还提供了很多高级功能,比如规则的优先级、推理机制、事实监听和动态更新等等
  • 规则的优先级可以在规则定义中通过 salience 关键字进行设置,例如:
rule "High Priority Rule"
    salience 10
    when
        ...
    then
        ...
end

在这个规则中,我们使用 salience 设置了规则的优先级为10。也就是说,当此规则被匹配时,它会先于优先级低的规则被执行。

需要注意的是,优先级并不是越高越好,它应该根据具体业务场景来设置。如果规则之间有相互依赖的关系,那么优先级的设定就尤为关键。

另外,如果多个规则的优先级相同,Drools 在执行时会随机选择一个规则执行。如果希望优先级相同时按照某种特定的顺序执行规则,可以通过设置 agenda-group 来实现,例如:


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

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


例子中,我们将规则1和规则2分别设置在同一个 agenda-group 中,并且它们的优先级相同,这时,它们会按照代码中定义的顺序被执行。

Drools 是用 Java 语言编写的开放源码规则引擎,使用 Rete 算法对所编写的规则求值。Drools 允许使用声明方式表达业务逻辑。可以使用非 XML 的本地语言编写规则,从而便于学习和理解。并且,还可以将 Java 代码直接嵌入到规则文件中,这令 Drools 的学习更加吸引人。

官方解释:
Rete(REtE是一种高效的规则匹配算法,它是由 MIT 奥林匹克研究计划(Project Athena)的控制与互联控制部门主任 Charles Forgy 在 1979 年提出的,是现今知名的规则引擎 Drools 引擎中匹配部分的核心基础算法之一。

Rete 算法是一种基于产生消费模型(Production-Consumption)的算法,它将规则匹配转换成了规则验证问题。算法思路是:当一条新的事实(Fact)被插入到工作内存(Working Memory)中时,Rete 算法通过前缀网络(Prefix Network)逐一匹配所有与此事实相关的规则;对于已经匹配的规则,则会将它们加入到决策表(Agenda Table)中,等待规则执行引擎进行规则的进一步处理。

可以看出,Rete 算法支持大规模的规则匹配,具有高效性和可扩展性。此外,Rete 算法还支持对规则的动态修改和删除,可以避免在修改规则时需要重新编译整个规则库的问题。

因此,Rete 算法是规则引擎实现的重要基础,常被用于规则引擎的核心功能实现。

一个简单的 Java 示例,演示了如何使用 Drools 的 Rete 算法实现规则匹配:

import org.drools.core.impl.InternalKnowledgeBase;
import org.drools.core.impl.KnowledgeBaseFactory;
import org.drools.core.impl.StatelessKnowledgeSessionImpl;
import org.drools.core.rule.Declaration;
import org.drools.core.rule.Pattern;
import org.drools.core.rule.Rule;
import org.drools.core.spi.PatternExtractor;
import org.drools.core.spi.PatternVariableExtractor;
import org.drools.core.spi.Tuple;
import java.util.Arrays;

public class ReteAlgorithmExample {

    public static void main(String[] args) {
        // 创建一个规则引擎知识库
        InternalKnowledgeBase knowledgeBase = KnowledgeBaseFactory.newKnowledgeBase();

        // 定义一个规则
        Rule rule = new Rule("SampleRule");

        // 定义匹配原语
        Pattern p = new Pattern(0, Arrays.asList(new Declaration[]{ }), "Person");
        p.addConstraint("age > 18");

        // 规则添加匹配原语
        rule.addPattern(p);

        // 定义规则条件和结果
        String condition = "System.out.println(\"Rule matched!\");";
        rule.setConsequence(condition);

        // 将规则添加到知识库
        knowledgeBase.addRule(rule);

        // 创建一个状态无关会话(Stateless Session)实例,用于执行规则
        StatelessKnowledgeSessionImpl session = new StatelessKnowledgeSessionImpl(knowledgeBase);

        // 初始化一个 Person 对象,插入到会话中
        Tuple tuple = session.getWorkingMemoryEntryPoint("DEFAULT").insert(new Person("Tom", 20));

        // 将会话匹配并执行所有规则
        session.fireAllRules();

        // 销毁会话实例
        session.dispose();
    }

    // 定义一个简单的数据模型
    public static class Person {
        private String name;
        private int age;

        public Person(String name, int age) {
            this.name = name;
            this.age = age;
        }

        public String getName() {
            return name;
        }

        public int getAge() {
            return age;
        }
    }
}



首先创建了一个规则,然后在规则中定义了一个匹配原语 Pattern,它匹配年龄大于 18 的 Person 对象。在规则被匹配成功时,我们将输出 “Rule matched!” 的信息。

接下来,我们创建了一个 StatelessKnowledgeSessionImpl 实例,它被用于执行规则,将创建的 Person 对象插入会话中,并通过 fireAllRules() 方法来触发规则引擎对规则进行匹配。当规则匹配成功时,Rete 算法会调用规则的 setConsequence() 方法,输出 “Rule matched!” 的信息。

链接:https://juejin.cn/post/7241966801214341177

 

请登录后发表评论

    没有回复内容