美文网首页收藏
drools中Fact的equality modes

drools中Fact的equality modes

作者: huan1993 | 来源:发表于2022-05-14 16:21 被阅读0次

    一、equality modes介绍

    drools中存在如下2种equality modes。

    1、identity模式

    identity:这是默认的情况。drools引擎使用IdentityHashMap保存所有插入到工作内存中的Fact对象。对于每次插入一个新的对象,则会返回一个新的FactHandle对象。如果是重复插入对象,则返回已经存在的FactHandle对象。

    举例:

    Person p1 = new Person("zhangsan", 20, "湖北罗田");
    Person p2 = new Person("zhangsan", 20, "湖北黄冈罗田");
    
    FactHandle factHandle1 = kieSession.insert(p1);
    FactHandle factHandle2 = kieSession.insert(p2);
    FactHandle factHandle3 = kieSession.insert(p2);
    

    针对以上例子, factHandle1 != factHandle2但是 factHandle2 == factHandle3。即工作内存中会存在2个Person对象。

    2、equality模式

    equality:drools引擎使用HashMap保存所有插入到工作内存中的Fact对象。在这种模式下,如果向drools中插入一个新的对象,只有这个对象不存在(根据对象的hashcodeequals判断)才会返回一个新的FactHandle否则返回已经存在的FactHandle

    举例:

    // 重写了Person对象的hashcode和equals方法
    Person p1 = new Person("zhangsan", 20, "湖北罗田");
    Person p2 = new Person("zhangsan", 20, "湖北黄冈罗田");
    
    FactHandle factHandle1 = kieSession.insert(p1);
    FactHandle factHandle2 = kieSession.insert(p2);
    FactHandle factHandle3 = kieSession.insert(p2);
    

    针对以上例子, factHandle1 == factHandle2但是 factHandle2 == factHandle3。即工作内存中会存在1个Person对象。

    二、需求

    我们存在一个Person对象,存在如下3个属性name,age和address,其中重写对象的name和age的hashcode和equals方法。

    1. 多次向工作内存中插入对象,看产生的结果。
    2. 插入同一个对象看获取到的FactHandle对象是否是同一个。

    三、如何设置fact对象的equality行为

    此处介绍一个通过kmodule.xml配置的方法

    <kmodule xmlns="http://www.drools.org/xsd/kmodule">
        <kbase name="kbase-identity" packages="rules" default="false" equalsBehavior="identity">
            <ksession name="ksession-01" default="false" type="stateful"/>
        </kbase>
        <kbase name="kbase-equality" packages="rules" default="false" equalsBehavior="equality">
            <ksession name="ksession-02" default="false" type="stateful"/>
        </kbase>
    </kmodule>
    

    通过上方的代码可知是通过配置kbase下的equalsBehavior属性来配置。

    其余的配置方法,参考下图:

    01-设置fact对象的equality行为.jpg

    四、编码实现

    1、项目结构图

    02-项目结构图.jpg

    2、倒入jar包

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.drools</groupId>
                <artifactId>drools-bom</artifactId>
                <type>pom</type>
                <version>7.69.0.Final</version>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    
    <dependencies>
        <dependency>
            <groupId>org.drools</groupId>
            <artifactId>drools-compiler</artifactId>
        </dependency>
        <dependency>
            <groupId>org.drools</groupId>
            <artifactId>drools-mvel</artifactId>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.11</version>
        </dependency>
    </dependencies>
    

    3、编写Person对象

    public class Person {
        private String name;
        private Integer age;
        private String address;
    
        public Person(String name, Integer age, String address) {
            this.name = name;
            this.age = age;
            this.address = address;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public Integer getAge() {
            return age;
        }
    
        public void setAge(Integer age) {
            this.age = age;
        }
    
        public String getAddress() {
            return address;
        }
    
        public void setAddress(String address) {
            this.address = address;
        }
    
        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            Person person = (Person) o;
            return Objects.equals(name, person.name) && Objects.equals(age, person.age);
        }
    
        @Override
        public int hashCode() {
            return Objects.hash(name, age);
        }
    }
    
    

    注意:
    此对象需要重写hashcode和equals方法。

    4、编写kmodule.xml文件

    在此配置文件中,需要在kbase上指定equalsBehavior,用来确定Fact对象的equality modes。

    <kmodule xmlns="http://www.drools.org/xsd/kmodule">
        <kbase name="kbase-identity" packages="rules" default="false" equalsBehavior="identity">
            <ksession name="ksession-01" default="false" type="stateful"/>
        </kbase>
        <kbase name="kbase-equality" packages="rules" default="false" equalsBehavior="equality">
            <ksession name="ksession-02" default="false" type="stateful"/>
        </kbase>
    </kmodule>
    

    注意:
    需要看2个equalsBehavior的取值

    5、编写一个规则文件

    package rules
    
    import com.huan.drools.Person
    
    // 定义规则
    rule "rule_01"
        when
            $p: Person()
        then
            System.out.println(Thread.currentThread().getName() + " name:"+$p.getName()+" age:"+$p.getAge());
    end
    

    规则文件中的内容很简单,只要工作内存中存在Person对象,那么就输出这个对象的nameage的值。

    6、identity模式测试

    1、编写测试代码

    public class DroolsApplication {
        public static void main(String[] args) {
            equalsBehaviorIdentity();
        }
    
        private static void equalsBehaviorIdentity() {
            KieServices kieServices = KieServices.get();
            KieContainer kieContainer = kieServices.getKieClasspathContainer();
            // 注意此处的 ksession-01
            KieSession kieSession = kieContainer.newKieSession("ksession-01");
            kieSession.addEventListener(new DebugRuleRuntimeEventListener());
    
            Person p1 = new Person("zhangsan", 20, "湖北罗田");
            Person p2 = new Person("zhangsan", 20, "湖北黄冈罗田");
    
            FactHandle factHandle1 = kieSession.insert(p1);
            FactHandle factHandle2 = kieSession.insert(p2);
            FactHandle factHandle3 = kieSession.insert(p2);
            kieSession.fireAllRules();
    
            kieSession.dispose();
        }   
    }
    

    2、运行结果

    03-identity.jpg

    具体的解释见上图中的说明。

    7、equality模式测试

    1、编写测试代码

    public class DroolsApplication {
        public static void main(String[] args) {
            equalsBehaviorEquality();
        }
    
        private static void equalsBehaviorEquality() {
            KieServices kieServices = KieServices.get();
            KieContainer kieContainer = kieServices.getKieClasspathContainer();
            KieSession kieSession = kieContainer.newKieSession("ksession-02");
            kieSession.addEventListener(new DebugRuleRuntimeEventListener());
    
            Person p1 = new Person("zhangsan", 20, "湖北罗田");
            Person p2 = new Person("zhangsan", 20, "湖北黄冈罗田");
    
            FactHandle factHandle1 = kieSession.insert(p1);
            FactHandle factHandle2 = kieSession.insert(p2);
            FactHandle factHandle3 = kieSession.insert(p2);
            kieSession.fireAllRules();
    
            kieSession.dispose();
        }
    }
    

    2、运行结果

    04-equality.jpg

    五、结论

    针对如下代码,看看在不同equality modes下的行为

     Person p1 = new Person("zhangsan", 20, "湖北罗田");
     Person p2 = new Person("zhangsan", 20, "湖北黄冈罗田");
    
     FactHandle factHandle1 = kieSession.insert(p1);
     FactHandle factHandle2 = kieSession.insert(p2);
     FactHandle factHandle3 = kieSession.insert(p2);
    

    Person对象的hashcode和equals方法进行重写了,根据构造方法的前2个参数。

    1、identity模式下

    factHandle1 != factHandle2 因为p1和p2是2个不同的对象。
    factHandle2 == factHandle3 因为是p2重复加入工作内存,这个时候工作内存中已经存在了,所以返回之前关联的FactHandle

    2、equality模式下

    factHandle1 == factHandle2 == factHandle3 因为这种模式下,是需要根据对象的equalshashcode方法进行比较,而Person对象重写了这2个方法,所以返回的是同一个。

    六、完整代码

    https://gitee.com/huan1993/spring-cloud-parent/tree/master/drools/drools-fact-equality-modes

    七、参考链接

    1、https://docs.drools.org/7.69.0.Final/drools-docs/html_single/index.html#fact-equality-modes-con_decision-engine

    相关文章

      网友评论

        本文标题:drools中Fact的equality modes

        本文链接:https://www.haomeiwen.com/subject/irqmurtx.html