Aviator 规则引擎介绍

先说结论: 规则简单:qlexpress或者avaitor;规则复杂:drools

最终选择是因为:足够轻量级,社区活跃度较好,最新jar包更新于22年4月

String expression = "a=='河北省'&&((b=='男人'||c>=30)||d=='黄')";

    // 编译表达式
    Expression compiledExp = AviatorEvaluator.compile(expression);

    Map<String, Object> env = new HashMap<>();
    env.put("a", "河北省");
    env.put("b", "男人");
    env.put("c",1);
    env.put("d","黄");


    // 执行表达式
    System.out.println( compiledExp.execute(env));

1、引入背景

1.1 需求背景及面临问题

系统分案时,需要针对规则进行解析:
示例:
((省份 = 河北省)并且((城市 = 张家口市)或者(城市 = 石家庄市))并且(服务类型 = 信用卡)并且((委托金额 > 1000)并且(委托金额 < 50000)))或者((省份 = 河北省)并且(城市 = 石家庄市)并且(服务类型 = 互联网))
解析条件:
(省份 = 河北省)并且(城市 = 张家口市)并且(服务类型 = 信用卡)并且(委托金额 > 1000)并且(委托金额 < 50000)
(省份 = 河北省)并且(城市 = 石家庄市)并且(服务类型 = 信用卡)并且(委托金额 > 1000)并且(委托金额 < 50000)
(省份 = 河北省)并且(城市 = 石家庄市)并且(服务类型 = 互联网)

1.2 面临问题

系统架构复杂
系统的可维护性和维护成本提高
系统的整合复杂
增加“硬代码”业务规则的成本和风险

2 为什么选用Aviator

2.1 简介

高性能、轻量级的java语言实现的表达式求值引擎,主要用于各种表达式的动态求值
Aviator的设计目标是轻量级和高性能 ,相比于Groovy、JRuby的笨重,Aviator 非常小,加上依赖包也才450K,不算依赖包的话只有70K
其次,Aviator的实现思路与其他轻量级的求值器很不相同,其他求值器一般都 是通过解释的方式运行,而Aviator则是直接将表达式编译成Java字节码,交给 JVM去执行
简单来说,Aviator的定位是介于Groovy这样的重量级脚本语言和 IKExpression这样的轻量级表达式引擎之间。

2.2 特性介绍

支持大部分运算操作符,包括算术操作符、关系运算符、逻辑操作符、正则匹配操作符 、三元表达式 ,并且支持操作符的优先级和括号强制优先级,具体请看后面的操作符列表。
支持函数调用和自定义函数。
支持正则表达式匹配,类似Ruby、Perl的匹配语法,并且支持类Ruby的$digit指向匹配分组。自动类型转换,当执行操作的时候,会自动判断操作数类型并做相应转换,无法转换即抛异常。
支持传入变量,支持类似a.b.c的嵌套变量访问。
性能优秀。

2.3 整体结构

在这里插入图片描述

3 demo

3.1 引入pom

为啥选这个版本,因为这是按时间倒序的第二个稳定版本

<!-- https://mvnrepository.com/artifact/com.googlecode.aviator/aviator -->
<dependency>
    <groupId>com.googlecode.aviator</groupId>
    <artifactId>aviator</artifactId>
    <version>5.3.0</version>
</dependency>

3.2 执行方式

execute():需要传递Map格式参数
exec():不需要传递Map


public class Test {
    public static void main(String[] args) {
        // exec执行方式,无需传递Map格式
        String age = "18";
        System.out.println(AviatorEvaluator.exec("'His age is '+ age +'!'", age));

        // execute执行方式,需传递Map格式
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("age", "18");
        System.out.println(AviatorEvaluator.execute("'His age is '+ age +'!'", map));

    }
}

3.3 支持函数


public class Test {
    public static void main(String[] args) {
        Map<String,Object> map = new HashMap<>();
        map.put("s1","123qwer");
        map.put("s2","123");

  System.out.println(AviatorEvaluator.execute("string.startsWith(s1,s2)",map));

    }
}

3.4 自定义函数

自定义函数要继承AbstractFunction类,重写目标方法。

public class Test {
    public static void main(String[] args) {
        // 注册自定义函数
        AviatorEvaluator.addFunction(new MultiplyFunction());
        // 方式1
        System.out.println(AviatorEvaluator.execute("multiply(12.23, -2.3)"));
        // 方式2
        Map<String, Object> params = new HashMap<>();
        params.put("a", 12.23);
        params.put("b", -2.3);
        System.out.println(AviatorEvaluator.execute("multiply(a, b)", params));
    }

}

class MultiplyFunction extends AbstractFunction{
    @Override
    public AviatorObject call(Map<String, Object> env, AviatorObject arg1, AviatorObject arg2) {

        double num1 = FunctionUtils.getNumberValue(arg1, env).doubleValue();
        double num2 = FunctionUtils.getNumberValue(arg2, env).doubleValue();
        return new AviatorDouble(num1 * num2);
    }

    @Override
    public String getName() {
        return "multiply";
    }

}

3.5 运算符优先级

在这里插入图片描述

3.6 常量和变量

在这里插入图片描述

3.7 表达式Demo


public class Test {
   public static void main(String[] args) {
       String expression = "a+(b-c)>100";
       // 编译表达式
       Expression compiledExp = AviatorEvaluator.compile(expression);

       Map<String, Object> env = new HashMap<>();
       env.put("a", 100.3);
       env.put("b", 45);
       env.put("c", -199.100);

       // 执行表达式
       Boolean result = (Boolean) compiledExp.execute(env);
       System.out.println(result);

   }
}

3.8 数组和集合Demo

List和数组用list[0]和array[0],Map用map.date

public class Test {
    public static void main(String[] args) {

        final List<String> list = new ArrayList<>();
        list.add("hello");
        list.add(" world");

        final int[] array = new int[3];
        array[0] = 0;
        array[1] = 1;
        array[2] = 3;

        final Map<String, Date> map = new HashMap<>();
        map.put("date", new Date());

        Map<String, Object> env = new HashMap<>();
        env.put("list", list);
        env.put("array", array);
        env.put("map", map);

        System.out.println(AviatorEvaluator.execute(
                "list[0]+':'+array[0]+':'+'today is '+map.date", env));

    }

}

3.9 三元比较符

public class Test {
    public static void main(String[] args) {

        Map<String, Object> env = new HashMap<String, Object>();
        env.put("a", -5);
        String result = (String) AviatorEvaluator.execute("a>0? 'yes':'no'", env);
        System.out.println(result);
    }

}

3.10 正则表达式匹配

public class Test {
    public static void main(String[] args) {
        String email = "hello2018@gmail.com";
        Map<String, Object> env = new HashMap<String, Object>();
        env.put("email", email);
        String username = (String) AviatorEvaluator.execute("email=~/([\\w0-8]+)@\\w+[\\.\\w+]+/ ? $1 : 'unknow' ", env);
        System.out.println(username);
    }
}

3.11 变量的语法糖衣



/**
 * CreateBy: haleyliu
 * CreateDate: 2018/12/25
 */
public class Test {
    public static void main(String[] args) {
        User user = new User(1,"jack","18");
        Map<String, Object> env = new HashMap<>();
        env.put("user", user);

        String result = (String) AviatorEvaluator.execute(" '[user id='+ user.id + ',name='+user.name + ',age=' +user.age +']' ", env);
        System.out.println(result);
    }
}


@Data
@AllArgsConstructor
@NoArgsConstructor
@NoArgsConstructor
@ToString
public class User {

    private int id;

    private String name;

    private String age;

    public User() {
    }

  

}

3.12 nil对象[任何对象都比nil大除了nil本身]


        AviatorEvaluator.execute("nil == nil");  //true 
        AviatorEvaluator.execute(" 3> nil");    //true 
        AviatorEvaluator.execute(" true!= nil");    //true 
        AviatorEvaluator.execute(" ' '>nil ");  //true 
        AviatorEvaluator.execute(" a==nil ");   //true,a is null
nil与String相加的时候,跟java一样显示为null


3.13 日期比较

public class Test {
    public static void main(String[] args) {
        Map<String, Object> env = new HashMap<String, Object>();
        final Date date = new Date();
        String dateStr = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SS").format(date);
        env.put("date", date);
        env.put("dateStr", dateStr);

        Boolean result = (Boolean) AviatorEvaluator.execute("date==dateStr",env);
        System.out.println(result);

        result = (Boolean) AviatorEvaluator.execute("date > '2009-12-20 00:00:00:00' ", env);
        System.out.println(result);

        result = (Boolean) AviatorEvaluator.execute("date < '2200-12-20 00:00:00:00' ", env);
        System.out.println(result);

        result = (Boolean) AviatorEvaluator.execute("date ==date ", env);
        System.out.println(result);


    }
}

4 语法手册

4.1 数据类型

Number类型:数字类型,支持两种类型,分别对应Java的Long和Double

任何整数都将被转换为Long

任何浮点数都将被转换为Double,包括用户传入的数值也是如此转换。

不支持科学计数法

支持十进制。如-1、100、2.3等。

整数也可以用十六进制表示,以 0x 或者 0X 开头的数字,比如 0xFF(255)、0xAB(171) 等等。

需要注意,整数相除的结果仍然是整数,比如例子中的 a/b 结果就是 0,遵循 java 的整数运算规则。

String类型: 字符串类型

单引号或者双引号括起来的文本串,如’hello world’

变量如果传入的是String或者Character也将转为String类型。

Bool类型:

常量true和false,表示真值和假值,与java的Boolean.TRUE和Boolean.False对应。

Pattern类型:

类似Ruby、perl的正则表达式,以//括起来的字符串,如//d+/

内部实现为java.util.Pattern。

变量类型:

与Java的变量命名规则相同,

变量的值由用户传入,如"a"、"b"等

nil类型: 常量nil,类似java中的null,

但是nil比较特殊,nil不仅可以参与==、!=的比较,也可以参与>、>=、<、<=的比较,

Aviator规定任何类型都n大于nil除了nil本身,nil==nil返回true。

用户传入的变量值如果为null,那么也将作为nil处理,nil打印为null。

4.2 算术运算符

支持常见的算术运算符,包括+ - / % 五个二元运算符和一元运算符"-“。
其中 - / %和一元的”-"仅能作用于Number类型。
"+"不仅能用于Number类型,还可以用于String的相加,或者字符串与其他对象的相加。
Aviator规定,任何类型与String相加,结果为String。

4.3 逻辑运算符

Avaitor的支持的逻辑运算符包括,一元否定运算符"!“,以及逻辑与的”&&“,逻辑或的”||"。逻辑运算符的操作数只能为Boolean。

4.4 关系运算符

Aviator支持的关系运算符包括"<" “<=” “>” “>=” 以及"==“和”!=" 。

&&和||都执行短路规则。

关系运算符可以作用于Number之间、String之间、Pattern之间、Boolean之间、变量之间以及其他类型与nil之间的关系比较,不同类型除了nil之外不能相互比较。

Aviator规定任何对象都比nil大除了nil之外。

4.5 匹配运算符

匹配运算符"=~"用于String和Pattern的匹配,它的左操作数必须为String,右操作数必须为Pattern。
匹配成功后,Pattern的分组将存于变量$num,num为分组索引。

4.6 三元运算符

两种模式
默认AviatorEvaluator以编译速度优先:

AviatorEvaluator.setOptimize(AviatorEvaluator.COMPILE);
你可以修改为运行速度优先,这会做更多的编译优化:

AviatorEvaluator.setOptimize(AviatorEvaluator.EVAL);

  • 5
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
aviator规则引擎配置是指在使用aviator规则引擎的过程中,对其进行相关参数的设置和调整,以适应具体业务的需求和实际场景的要求。 配置aviator规则引擎通常包括以下几个方面: 1. 规则文件的加载:在使用aviator规则引擎之前,需要将规则文件加载到引擎中。规则文件可以是文本文件,也可以是数据库中的数据。通过适当的配置,可以指定规则文件的路径或者连接信息,使得引擎能够正确地加载和解析规则文件。 2. 规则变量的设置:规则引擎需要获取和设置一系列的规则变量,以进行规则的计算和推理。在配置引擎时,可以指定规则变量的名称、类型和初值,以及变量的作用域和可见性等。这样,在使用规则引擎时可以直接引用规则变量,进行相应的计算和判断。 3. 规则优先级的设定:规则引擎通常会包含多条规则,而这些规则有时候会有互相之间的冲突。通过设定规则的优先级,可以确定规则执行的先后顺序,从而在执行过程中遵循预期的逻辑。一般来说,可以通过给规则设置权重或者指定执行顺序的方式来设定规则的优先级。 4. 规则引擎选项的调整:aviator规则引擎通常提供了一系列的配置选项,用于控制规则的执行模式和行为。比如,可以通过设置最大执行时间、最大递归深度、启用缓存等选项来控制规则的执行效率和安全性。此外,还可以针对debug模式、编译模式和并发模式等方面进行相应的设置。 通过合理的配置,aviator规则引擎可以在各种复杂的场景下发挥出强大的计算和决策能力,提高系统的效率和灵活性。但是需要注意的是,配置规则引擎要根据具体的需求和条件,避免过度的调整和复杂的配置,以免引起不必要的性能开销或者错误。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员黄小青

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值