实际应用中的优化方案

使用Drools规则引擎时,很多初学者都会认为Drools的效果比较低,做一个例子,哪怕是写一些简单的规则也会要很多秒的时间,在如今的高并发下,要求的都是效果第一,其实这是初学者的一个误区,在实际开发过程,我们都是要进行优化的,小编就针对Drools优化做一个说明,具体的优化可从两个方向着手,第一:规则语法;第二:执行规则。怎么说呢,第一种方式我们好理解,“规则语法”,就是我们通常所说的Drl文件里的内容,我们知道,每一个规则就是一个if,我们也非常清楚在JAVA语法中AND的优化级是大于OR的,如果遇到有OR的情况,我们都会分成两个IF的方式,在DRL语法也是这样的,举个例子说明:

 

未优化的Drl:

package rules 

import  pojo.Rulecondition;
import  pojo.Person;


rule	Goodsdetail12
 no-loop true
 	when
 	    $r:Rulecondition(moneyMin>=100) OR $p: Person(name== "张三")
 	then
 	  。。。。。
end

优化的Drl:

package rules 

import  pojo.Rulecondition;
import  pojo.Person;

rule	Goodsdetail12
 no-loop true
 	when
 	    $r:Rulecondition(moneyMin>=100)
then
End

rule	Goodsdetail13
 no-loop true
 	when
 	   $p: Person(name== "张三")
 	then
End

WHEN优化第二种方式:

未优化的Drl:

package rules 
 
import  pojo.Person;


rule	Goodsdetail12
 no-loop true
 	when
 	   $p: Person(age>=50,name=="张三")
 	then
 	  。。。。。
end

读者看看,上面的规则有什么不妥嘛?很简单,这个道理与查询数据库是一样的,等于查询的数据是要比于区间的,所有,这里我们可以这样进行改造。

package rules 
 
import  pojo.Person;


rule	Goodsdetail12
 no-loop true
 	when
 	   $p: Person(name=="张三",age>=50)
 	then
 	  。。。。。
end

规则语法的整合优化:

为何要说规则语法的整合优化呢,其实规则在执行时,会有一个类似预处理的过程,也就是小编之前所说的,规则只执行满足条件的部分(如果使用accumulate可以测试),而规则并不是怕规则多,其实规则多少对整合性能影响并不是很大,只是在生成规则库时需要大量的时间。所有优化规则语法的原则为:

  • 规则拆分原则:将规则进行拆分,避免出现OR的情况
  • 规则比较原则:将区间或模糊查询的方式排在比较值的后面
  • 规则简单原则:尽量避免出现过于复杂比较值
  • 规则结果原则:then中避免出来if eles

 

说完语法的优化,那我们再来说一下执行规则的优化吧,这也是很多初学者很容易出的问题,执行规则,就不得不说Kiesession,我们知道,规则的一切操作离不开kiesession会话,而kiesession会话离不开规则库(Kiebase),大家一般在创建时,使用的都是kmodule.xml文件方式,大部分都直接使用代码:

        KieServices kss = KieServices.Factory.get();
        KieContainer kc = kss.getKieClasspathContainer();
        KieSession ks =kc.newKieSession("session");

我们可以做一个测试,这里就发现第三句code是最耗时的,小编在前面章节中介绍过KieContainer。其实我们看源码时,就会发现Kie容器是需要去创建规则库的,一般的写法应该是创建KieContainer创建出KieBase,通过Kiebase创建出Kiesession。那我们找到了问题的点了,也就是创建规则库时是最耗时的。那有什么方法可以解决呢,小编这里就给读者提方案:

如果规则在不变的情况下,我们是可以直接将针对于这一块业务创建的规则库进行内存级缓存,为何小编会这样说,缓存不是应该放在Redis里嘛?Redis放数据是需要序列化的,而KieBase是不能被放到redis中的,换句话说,规则库只能是当前内存级的(这里会衍生一个问题,下面的小编会点到的)。所有我们可以将规则库进行一个封装,做成全局类型的:

    public class  DroolsAct{
        private  static KieBase kieBase;
        … 下面再写一个创建规则库的方法就好了
    }

如果还先再进一步优化,那就再将Kiesession进行内存级缓存,道理与创建规则库是一样的,做成全局类型的:

    public class  DroolsAct{
        private  static KieBase kieBase;
        private  static Kiesession kiesession;
        … 下面再写一个创建规则库的方法就好了
    }

当然啦,小编这里肯定还有更好的方式了,这也是小编实际项目中写的方式:

封装一个规则库的javaBean

package com.util;

import com.model.work.AddSkuPresent;
import org.kie.api.KieBase;
import org.kie.api.runtime.StatelessKieSession;

import java.util.Date;
import java.util.List;

import static com.util.NewKieBase.rulekieBase;


public class PromoteExecute2 {
    private String sillContent;
    //业务规则内容:
    private String workContent;
    //业务Kbase
    private KieBase workKbase;
    //业务session
    private StatelessKieSession workSession;

    public String getSillContent() {
        return sillContent;
    }

    public void setSillContent(String sillContent) {
        this.sillContent = sillContent;
    }

    public String getWorkContent() {
        return workContent;
    }

    public void setWorkContent(String workContent) {
        this.workContent = workContent;
    }

    public KieBase getWorkKbase() {
        if (this.workKbase == null) {
            this.setWorkKbase();
        }
        return workKbase;
    }

    public void setWorkKbase() {
        this.workKbase = rulekieBase(this.getWorkContent());
    }

    public StatelessKieSession getWorkSession() {
        if (this.workSession == null) {
            this.setWorkSession();
        }
        return workSession;
    }
    public void setWorkSession() {
        if (null != this.getWorkKbase()) {
            this.workSession = this.getWorkKbase().newStatelessKieSession();
        }
    }
}

创建规则库方法:

package com.util;

import org.apache.commons.lang3.StringUtils;
import org.kie.api.KieBase;
import org.kie.api.io.ResourceType;
import org.kie.internal.utils.KieHelper;

public class NewKieBase {
    //将业务规则写到规则库中
    public static KieBase rulekieBase(String rule) {
        if(StringUtils.isBlank(rule)){
            return null;
        }
        KieHelper helper = new KieHelper();
        KieBase kieBase = null;
        try {
            helper.addContent(rule,ResourceType.DRL);
            kieBase = helper.build();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return kieBase;
    }
}

将上面的javaBean 进行引用就可以了。

后续优化待定…

记得小编说Kiebase只能是内存级的,不能进行缓存,会衍生出一个问题,那就是集群,如何能保证我们在集群应用时,用户调用访问的同一类的规则库呢,小编先将问题提出来,有想法的读者可以给小编发邮件kangzuguan@qq.com, 下期更新教程时,小编会提出自己的想法和解决方案。

 

 

 

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值