QLExpress 规则引擎使用介绍

一个轻量级的类java语法规则引擎,作为一个嵌入式规则引擎在业务系统中使用。让业务规则定义简便而不失灵活。让业务人员就可以定义业务规则。支持标准的JAVA语法,还可以支持自定义操作符号、操作符号重载、函数定义、宏定义、数据延迟加载等

QLExpress的特性

1、编译执行:

编译生成基础指令后执行,性能能得到基本保障。执行过程:单词分解-->单词类型分析-->语法分析-->生成运行期指令集合-->执行生成的指令集合

runner.execute("10 * 10 + 1 + 2 * 3 + 5 * 2", null, true,null);
最后生成的指令:
	1:LoadData 10
	2:LoadData 10
	3:OP : * OPNUMBER[2]
	4:LoadData 1
	5:OP : + OPNUMBER[2]
	6:LoadData 2
	7:LoadData 3
	8:OP : * OPNUMBER[2]
	9:OP : + OPNUMBER[2]
	10:LoadData 5
	11:LoadData 2
	12:OP : * OPNUMBER[2]
	13:OP : + OPNUMBER[2]

2、支持标准的java语法、JAVA运算符号和关键字

import:引入一个包或者类,例如:import java.util.*;需要放在脚本的最前面
new:创建一个对象,例如:new ArrayList();
for:操作符号
if:操作符号
then:操作符号
else:操作符号
break: 终止循环
continue: 绩效循环
return: 返回
     A、四则运算 : 10 * 10 + 1 + 2 * 3 + 5 * 2
     B、boolean运算: 3 > 2 and 2 > 3
     C、创建对象,对象方法调用,静态方法调用:new com.ql.util.express.test.BeanExample("张三").unionName("李四")
     D、变量赋值:a = 3 + 5
     E、支持 in,max,min:  (a in (1,2,4)) and (b in("abc","bcd","efg"))

3、自定义的关键字

include:在一个表达式中引入其它表达式。例如: include com.taobao.upp.b; 资源的转载可以自定义接口IExpressResourceLoader来实现,缺省是从文件中装载
[]:匿名创建数组.int[][] abc = [[11,12,13],[21,22,23]];
NewMap:创建HashMap. Map abc = NewMap(1:1,2:2);Map abc = NewMap("a":1,"b":2)
NewList:串接ArrayList.List abc = NewList(1,2,3);
exportDef: 将局部变量转换为全局变量,例如:exportDef long userId
alias:创建别名,例如: alias 用户ID user.userId
exportAlias: 创建别名,并转换为全局别名
macro: 定义宏,例如: macro 降级  {level = level - 1}
function: 定义函数,例如: function add(int a,int b){  return a+b; };
in: 操作符号,例如: 3 in (3,4,5)
mod:操作符号,例如:  7 mod 3
like:操作符号,例如: "abc" like ‘ab%‘

4、自定义的系统函数,后续还会不断的添加

   max:取最大值max(3,4,5)
   min:最最小值min(2,9,1)
   round:四舍五入round(19.08,1)
   print:输出信息不换行print("abc")
   println:输出信息并换行 println("abc")

5、提供表达式上下文,属性的值不需要在初始的时候全部加入,而是在表达式计算的时候,需要什么信息才通过上下文接口获取。

避免因为不知道计算的需求,而在上下文中把可能需要的数据都加入。
runner.execute("三星卖家 and 消保用户",errorList,true,expressContext) "三星卖家"和"消保用户"的属性是在需要的时候通过接口去获取。

6、可以将计算结果直接存储到上下文中供后续业务使用。例如:

  runner.execute("c = 1000 + 2000",errorList,true,expressContext);
  则在expressContext中会增加一个属性c=3000,也可以在expressContext实现直接的数据库操作等。

7、支持高精度浮点运算,只需要在创建执行引擎的时候指定参数即可:new ExpressRunner(true,false);
8、可以将Class和Spring对象的方法映射为表达式计算中的别名,方便其他业务人员的立即和配置。例如

     将 Math.abs() 映射为 "取绝对值"。
      runner.addFunctionOfClassMethod("取绝对值", Math.class.getName(), "abs",new String[] { "double" }, null);
      runner.execute("取绝对值(-5.0)",null,true,null);

9、可以为已经存在的boolean运算操作符号设置别名,增加错误信息同步输出,在计算结果为false的时候,同时返回错误信息,减少业务系统相关的处理代码

   runner.addOperatorWithAlias("属于", "in", "用户$1不在允许的范围")。
   用户自定义的函数同样也可以设置错误信息:例如:
   runner.addFunctionOfClassMethod("isOk", BeanExample?.class.getName(),"isOk", new String[] { "String" }, "$1 不是VIP用户");
  则在调用:
     List errorList = new ArrayList?();
     Object result =runner.execute("( (1+1) 属于 (4,3,5)) and isOk("玄难")",errorList,true,null);
     执行结果 result = false.同时在errorList中还会返回2个错误原因:
         1、"用户 2 不在允许的范围"
         2、玄难 不是VIP用户

10、可以自定义函数,自定一个操作函数 group

class GroupOperator extends Operator {
	public GroupOperator(String aName) {
		this.name= aName;
	}
	public Object executeInner(Object[] list)throws Exception {
		Object result = new Integer(0);
		for (int i = 0; i < list.length; i++) {
			result = OperatorOfNumber.Add.execute(result, list[i]);
		}
		return result;
	}
}

则执行:

     runner.addFunction("累加", new GroupOperator("累加"));
     runner.addFunction("group", new GroupOperator("group"));
    //则执行:group(2,3,4)  = 9 ,累加(1,2,3)+累加(4,5,6)=21

11、可以自定操作符号。自定义的操作符号优先级设置为最高。例如自定一个操作函数 love:

class LoveOperator extends Operator {
	public LoveOperator(String aName) {
		this.name= aName;
	}
	public Object executeInner(Object[] list)
			throws Exception {
		String op1 = list[0].toString();
		String op2 = list[1].toString();
		String result = op2 +"{" + op1 + "}" + op2;
		return result;
	}
}

然后增加到运算引擎:

 runner.addOperator("love", new LoveOperator("love"));
    //则执行:‘a‘ love ‘b‘ love ‘c‘ love ‘d‘ = "d{c{b{a}b}c}d"

12、可以重载已有的操作符号。例如替换“+”的执行逻辑。参见:com.ql.util.express.test.ReplaceOperatorTest
13、可以延迟运算需要的数据
14、一个脚本可以调用其它脚本定义的宏和函数.参见com.ql.util.express.test.DefineTest
15、可以类似VB的语法来使用操作符号和函数。print abc; 等价于 print(abc).参见 com.ql.util.express.test.OpCallTest
16、支持类定义
17、对 in 操作支持后面的是一个数组或者List变量义

最典型的应用场景

在业务系统中存在一些逻辑判断,例如"商品A"只能是三星卖家,而且已经开通淘宝店铺的用户才能订购。
那么我们期望业务人员看到的配置信息就是:"三星卖家 而且 已经开店"
则通过下列步骤可能实现这个功能:

1、定义一个用户信息对象:

class UserInfo {
	long id;
	long tag;
        String name;

	public UserInfo(long aId,String aName, long aUserTag) {
		this.id = aId;
		this.tag = aUserTag;
		this.name = aName;
	}
        public String getName(){
    	   return name;
        }
	public long getUserId() {
		return id;
	}

	public long getUserTag() {
		return tag;
	}
}

2、定义两个基础的功能函数:

   /**
     * 判断一个用户TAG的第X位是否为1。这个的demo,其实现合理性不考虑
     * @param user
     * @param tagBitIndex
     * @return
     */
    public boolean userTagJudge(UserInfo user,int tagBitIndex){
    	boolean r =  (user.getUserTag() & ((long)Math.pow(2, tagBitIndex))) > 0;
    	return r;
    }

	/**
	 * 判断一个用户是否订购过某个商品
	 * @param user
	 * @param goodsId
	 * @return
	 */
	public boolean hasOrderGoods(UserInfo user,long goodsId){
		//随机模拟一个
		if(user.getUserId() % 2 == 1){
			return true;
		}else{
			return false;
		}
	}

3、初始化语句执行器

	public void initial() throws Exception{
		runner.addOperatorWithAlias("而且","and",null);
		runner.addFunctionOfClassMethod("userTagJudge", Demo.class.getName(), "userTagJudge",
                            new String[] {UserInfo.class.getName(),"int"}, "你不是三星卖家");
		runner.addFunctionOfClassMethod("hasOrderGoods", Demo.class.getName(), "hasOrderGoods",
                            new String[] {UserInfo.class.getName(),"long"}, "你没有开通淘宝店铺");
		runner.addMacro("三星卖家", "userTagJudge(userInfo,3)");//3表示三星卖家的标志位
		runner.addMacro("已经开店", "hasOrderGoods(userInfo,100)");//100表示旺铺商品的ID
	}

4、定义一个逻辑判断函数:

	/**
	 * 判断逻辑执行函数
	 * @param userInfo
	 * @param expression
	 * @return
	 * @throws Exception
	 */
	public String hasPermission(UserInfo userInfo,String expression) throws Exception {
        	IExpressContext<String,Object> expressContext = new DefaultContext<String,Object>();
    		expressContext.put("userInfo",userInfo);
    		List<String> errorInfo = new ArrayList<String>();
            Boolean result = (Boolean)runner.execute(expression, expressContext, errorInfo, true, false);
            String resultStr ="";
            if(result.booleanValue() == true){
            	resultStr = "可以订购此商品";
            }else{
              for(int i=0;i<errorInfo.size();i++){
            	  if(i > 0){
            		  resultStr  = resultStr + "," ;
            	  }
            	  resultStr  = resultStr + errorInfo.get(i);
              }
              resultStr = resultStr  + ",所以不能订购此商品";
            }
            return "亲爱的" + userInfo.getName() + " : " + resultStr;
    }

5、调用执行器执行判断逻辑:

	public static void main(String args[]) throws Exception{
		Demo demo = new Demo();
		demo.initial();
		System.out.println(demo.hasPermission(new UserInfo(100,"xuannan",7),  "三星卖家   而且   已经开店"));
		System.out.println(demo.hasPermission(new UserInfo(101,"qianghui",8), "三星卖家   而且   已经开店"));
		System.out.println(demo.hasPermission(new UserInfo(100,"张三",8), "三星卖家 and 已经开店"));
		System.out.println(demo.hasPermission(new UserInfo(100,"李四",7), "三星卖家 and 已经开店"));

参考资料

http://code.taobao.org/p/QLExpress/wiki/index/

原文地址:https://www.cnblogs.com/duanxz/p/9307985.html

时间: 2024-07-30 12:06:40

QLExpress 规则引擎使用介绍的相关文章

规则引擎以及blaze 规则库的集成初探之三——Blaze规则引擎和SRL

原文地址:http://jefferson.iteye.com/blog/68604 在上面介绍利用JSR94的api使用的章节中,我们使用的具体引擎的实现是一个商业产品,如果想了解Drools的使用,这里有一份入门的参考文章:http://blog.csdn.net/tigerflower/archive/2006/09/06/1185922.aspx.由于关于blaze的文章很少,这里根据经验,简单介绍一下它的实现. blaze是由blazeSoft公司提供的产品,由于是商业产品,因此专门I

.Net规则引擎介绍 - REngine

规则引擎 规则引擎由推理引擎发展而来,是一种嵌入在应用程序中的组件,实现了将业务决策从应用程序代码中分离出来,并使用预定义的语义模块编写业务决策.接受数据输入,解释业务规则,并根据业务规则做出业务决策. 个人理解 变化点过于集中在一点,为了适应变化,而给各种场景分别写了各自关于那点的代码逻辑,尽管主要的业务逻辑相同. 适用点举例 计算折扣,需要根据客户的积分决定打折点 工作流具体节点的路由控制 其他(希望大家补充下,想象力有限...) 用法 以计算客户打折点为例: 我们首先得新建一个规则文件,用

规则引擎QLExpress的简单应用

QLExpress 是一个轻量级的类java语法规则引擎,作为一个嵌入式规则引擎在业务系统中使用.让业务规则定义简便而不失灵活.让业务人员就可以定义业务规则.支持标 准的JAVA语法,还可以支持自定义操作符号.操作符号重载. 函数定义.宏定义.数据延迟加载等. QLExpress可以执行标准的java语法,例如 '哈哈'.equals('哈哈').if(true) {1} else{2}等,可以动态获取运算结果. QLExpress 3.0.6下载地址:http://code.taobao.or

SNF快速开发平台--规则引擎介绍和使用文档

设计目标: a) 规则引擎语法能够满足分单,计费,WMS策略的配置要求.语法是一致和统一的 b) 能够在不修改规则引擎模块的情况下,加入任意一个新的规则:实现上述需求之外的规则配置需求 c) 运算速度快 d) 有良好的展现效果,能够在售前阶段帮助销售 e) 提供良好的调试和诊断手段,便于配置规则 可以把以前固定写的业务逻辑,特别不确定的那种和变化比较多的写到规则中去.这样在实施时不同客户有各种各样的需求,可以按需配置,并不能修改程序代码,这样就更灵活. 并且我们实现的日志跟踪调试,运算符.条件语

几个常见规则引擎的简单介绍和演示

Ilog JRules 是最有名的商用BRMS: Drools 是最活跃的开源规则引擎: Jess 是Clips的java实现,就如JRuby之于Ruby,是AI系的代表: Visual Rules(旗正规则引擎)国内商业规则引擎品牌. 今天对比了一下这四个颇有代表性的规则引擎的规则语言.其中Ilog和visual rules是商业产品,没有机会实战. 1.一样的If--Then 句式与Rete引擎 四者都邑把原本杂乱不勘的if---else---elseif----else,拆成N条带优先级的

使用规则引擎Drools计算圆周率PI

实际上是使用规则引擎能够更新工作内存区重新匹配规则实现迭代功能. 使用了策略模式实现. <规则引擎与RETE算法介绍> PPT : http://files.cnblogs.com/lovesqcc/%E8%A7%84%E5%88%99%E5%BC%95%E6%93%8E%E4%B8%8ERETE%E7%AE%97%E6%B3%95.pptx 1.  CalcPI.java package sample; import java.util.ArrayList; import java.util

IBM规则引擎(ODM)入门系列二:Rule Execution Server(RES)服务安装

今天开始了ODM入门系列之二,在这个系列中我会讲讲规则执行服务的搭建安装,规则集的打包发布以及如何将部署之后的规则集发布为web服务,供其他服务或应用使用. 首先,我们先看一幅图: 这是我画的一张ODM各组件之间关系,其中WEB APP是我们自己的项目或应用,可以通过web服务的形式来调用RES上已经部署的RuleApp包来执行规则. 再来看一张图: (截屏自IBM官网) 这是IBM官网上的一张介绍ODM不同组件如何交互的一张图. 从这两张图都可以看出RES在ODM整个产品中都起着一个非常重要的

drools规则引擎因为内存泄露导致的内存溢出

进入这个问题之前,先了解一下drools: 在很多行业应用中比如银行.保险领域,业务规则往往非常复杂,并且规则处于不断更新变化中,而现有很多系统做法基本上都是将业务规则绑定在程序代码中. 主要存在的问题有以下几个方面: 1) 当业务规则变更时,对应的代码也得跟着更改,每次即使是小的变更都需要经历开发.测试验证上线等过程,变更成本比较大. 2) 长时间系统变得越来越难以维护. 3) 开发团队一般是由一个熟悉业务的BA(业务分析人员)和若干个熟悉技术的开发人员组成,开发人员对业务规则的把握能力远不及

基于NXBRE规则引擎实现的柔性折扣策略

规则引擎由推理引擎发展而来,是一种嵌入在应用程序中的组件,实现了将业务决策从应用程序代码中分离出来,并使用预定义的语义模块编写业务决策.接受数据输入,解释业务规则,并根据业务规则做出业务决策.应用背景: 企业级管理者对企业IT系统的开发有着如下的要求: 1. 为提高效率,管理流程必须自动化,即使现代商业规则异常复杂. 2. 市场要求业务规则经常变化,IT系统必须依据业务规则的变化快速.低成本的更新. 3. 为了快速.低成本的更新,业务人员应能直接管理IT系统中的规则,不需要程序开发人员参与. 下