赞
踩
近期需要用到规则引擎来做数据处理和威胁检测引擎,所以对市面上常见的集中常见的规则引擎常用的几种技术方案做了调研,我采用同样的规则,
业务规则:
订单金小于100,给予积分0;
订单金额(100,500],给予积分100;
订单金额(500,1000],给予积分500;
订单金额(1000,+&],给予积分1000;
分别采用下面规则引擎执行100万次、1000万次、5000万次,每个场景执行3次取平均值得出如下表格的结果,从性能测试结果来看,groovy胜出,性能最佳。
执行次数\规则引擎 | QLExpression (ms) | groovy (ms) | drools (ms) | v8 |
---|---|---|---|---|
100w | 1590 | 171 | 364 | NA |
1000w | 12551 | 709 | 3530 | NA |
5000w | 60230 | 3516 | 19414 | NA |
由于v8采用js编码,执行性能较低,没有列入其中进行比较;
规则引擎 | QLExpression | groovy | drools |
---|---|---|---|
动态规则 | 支持 | 支持 | 支持 |
灵活性 | 低 | 高 | 中 |
复杂度 | 低 | 高 | 中 |
上手 | 快 | 慢 | 慢 |
使用广度 | 中 | 中 | 高 |
三种规则引擎都支持动态规则,可以通过提供的api动态扩展规则,灵活性上看groovy和drools支持脚本编写方式,市面上有常见的包装方案;其中QL在中小企业应用较广泛对熟悉java的选手来说基本开箱即用,groovy和drools作为规则引擎在互联网企业应用较多,有一定的学习和培训成本,drools追随者更多适用面积更广泛;
核心的测试代码如下
groovy
- /**
- * @ClassName GroovyApplication
- * @Description: TODO
- * @Author ikong
- * @Date 2022/5/30
- * @Version V1.0
- **/
- public class GroovyOrderScoreApplication {
-
- private static String BASIC_FILE_DIR_PATH = "/Users/ikong/demo/rule-engine-demo/rule-engine-demo-groovy/";
-
- private static String GROOVY_FILE_DIR_PATH = BASIC_FILE_DIR_PATH + "src/main/resources/groovy/";
-
- private static String GROOVY_ORDER01_SCRIPT = GROOVY_FILE_DIR_PATH + "order01_java.groovy";
-
- private static String GROOVY_G_SCRIPT = "test02_script.groovy";
-
- private static String GROOVY_P_SCRIPT = "test03_param.groovy";
-
- public static void main(String[] args) throws Exception {
- executeJava();//groovy 执行java编写的规则代码
- }
-
-
- private static void executeJava() throws Exception {
-
- //方式一调用groovy文件
- ClassLoader parent = GroovyOrderScoreApplication.class.getClassLoader();
- GroovyClassLoader loader = new GroovyClassLoader(parent);
- Class groovyClass = loader.parseClass(new File(GROOVY_ORDER01_SCRIPT));
- //得到groovy对象
- GroovyObject groovyObject = (GroovyObject) groovyClass.newInstance();
-
- List<Order> orderList = getInitData();
-
- int count = 200000;
- long now = System.currentTimeMillis();
-
- for (int j = 0; j < count; j++) {
- for (int i = 0; i < orderList.size(); i++) {
- Order order = orderList.get(i);
- groovyObject.setProperty("order", order);
- groovyObject.invokeMethod("apply", null);
- }
- }
-
- long cost = System.currentTimeMillis() - now;
-
- System.out.println("drools程序执行:" + count + "次,耗时:" + cost + "ms");
-
- }
-
-
- private static List<Order> getInitData() throws Exception {
- List<Order> orderList = new ArrayList<Order>();
- DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
- {
- Order order = new Order();
- order.setAmout(80);
- order.setBookingDate(df.parse("2015-07-01"));
- User user = new User();
- user.setLevel(1);
- user.setName("Name1");
- order.setUser(user);
- order.setScore(111);
- orderList.add(order);
- }
- {
- Order order = new Order();
- order.setAmout(200);
- order.setBookingDate(df.parse("2015-07-02"));
- User user = new User();
- user.setLevel(2);
- user.setName("Name2");
- order.setUser(user);
- orderList.add(order);
- }
- {
- Order order = new Order();
- order.setAmout(800);
- order.setBookingDate(df.parse("2015-07-03"));
- User user = new User();
- user.setLevel(3);
- user.setName("Name3");
- order.setUser(user);
- orderList.add(order);
- }
- {
- Order order = new Order();
- order.setAmout(1500);
- order.setBookingDate(df.parse("2015-07-04"));
- User user = new User();
- user.setLevel(4);
- user.setName("Name4");
- order.setUser(user);
- orderList.add(order);
- }
- return orderList;
- }
-
- }

pom.xml
- <dependencies>
- <dependency>
- <groupId>org.codehaus.groovy</groupId>
- <artifactId>groovy-all</artifactId>
- <version>3.0.8</version>
- <type>pom</type>
- </dependency>
- <dependency>
- <groupId>org.codehaus.groovy</groupId>
- <artifactId>groovy</artifactId>
- <version>3.0.8</version>
- </dependency>
- <dependency>
- <groupId>org.codehaus.groovy</groupId>
- <artifactId>groovy-ant</artifactId>
- <version>3.0.8</version>
- </dependency>
- </dependencies>

Drools
- /**
- * @ClassName DroolsApplication
- * @Description: TODO
- * @Author ikong
- * @Date 2022/5/30
- * @Version V1.0
- **/
- public class DroolsApplication {
-
- /**
- * 计算额外积分金额 规则如下: 订单原价金额
- * 100以下, 不加分
- * 100-500 加100分
- * 500-1000 加500分
- * 1000 以上 加1000分
- *
- * @param args
- * @throws Exception
- */
- public static final void main(final String[] args) throws Exception {
- // KieServices is the factory for all KIE services
- KieServices ks = KieServices.Factory.get();
-
- // From the kie services, a container is created from the classpath
- KieContainer kc = ks.getKieClasspathContainer();
-
- execute(kc);
- }
-
-
- public static void execute(KieContainer kc) throws Exception {
- // From the container, a session is created based on
- // its definition and configuration in the META-INF/kmodule.xml file
- KieSession ksession = kc.newKieSession("point-rulesKS");
-
- List<Order> orderList = getInitData();
-
- for (int i = 0; i < orderList.size(); i++) {
- Order o = orderList.get(i);
- ksession.insert(o);
- ksession.fireAllRules();
- }
-
- int count = 200000;
- long now = System.currentTimeMillis();
-
- for (int j = 0; j < count; j++) {
- for (int i = 0; i < orderList.size(); i++) {
- Order o = orderList.get(i);
- ksession.insert(o);
- ksession.fireAllRules();
- }
- }
-
- long cost = System.currentTimeMillis() - now;
-
- System.out.println("drools程序执行:" + count + "次,耗时:" + cost + "ms");
-
- ksession.dispose();
-
- }
-
-
- private static List<Order> getInitData() throws Exception {
- List<Order> orderList = new ArrayList<Order>();
- DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
- {
- Order order = new Order();
- order.setAmout(80);
- order.setBookingDate(df.parse("2015-07-01"));
- User user = new User();
- user.setLevel(1);
- user.setName("Name1");
- order.setUser(user);
- order.setScore(111);
- orderList.add(order);
- }
- {
- Order order = new Order();
- order.setAmout(200);
- order.setBookingDate(df.parse("2015-07-02"));
- User user = new User();
- user.setLevel(2);
- user.setName("Name2");
- order.setUser(user);
- orderList.add(order);
- }
- {
- Order order = new Order();
- order.setAmout(800);
- order.setBookingDate(df.parse("2015-07-03"));
- User user = new User();
- user.setLevel(3);
- user.setName("Name3");
- order.setUser(user);
- orderList.add(order);
- }
- {
- Order order = new Order();
- order.setAmout(1500);
- order.setBookingDate(df.parse("2015-07-04"));
- User user = new User();
- user.setLevel(4);
- user.setName("Name4");
- order.setUser(user);
- orderList.add(order);
- }
- return orderList;
- }
- }

pom.xml
- <dependency>
- <groupId>org.drools</groupId>
- <artifactId>drools-core</artifactId>
- <version>${drools.version}</version>
- </dependency>
- <dependency>
- <groupId>org.drools</groupId>
- <artifactId>drools-compiler</artifactId>
- <version>${drools.version}</version>
- </dependency>
- <dependency>
- <groupId>org.apache.commons</groupId>
- <artifactId>commons-lang3</artifactId>
- <version>3.3.2</version>
- </dependency>
- <properties>
- <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
- <maven.compiler.source>1.8</maven.compiler.source>
- <maven.compiler.target>1.8</maven.compiler.target>
- <drools.version>7.0.0.Final</drools.version>
- <java.version>1.8</java.version>
- <tomcat.version>8.5.11</tomcat.version>
- </properties>
QLExpression
- public class QLExpressionApplication {
-
- private static ExpressRunner runner = new ExpressRunner();
-
- private static IExpressContext<String, Object> expressContext = new DefaultContext<String, Object>();
-
- public static void main(String[] args) throws Exception {
-
- String expression = "if (o.amout > 1000) return 1000;"
- + " if (o.amout > 500 && o.amout <= 1000) return 500 ;"
- + " if (o.amout > 100 && o.amout <= 500) return 100 ;"
- + " if (o.amout <= 100 ) return 0 ;";
-
-
- List<Order> orderList = getInitData();
- int count = 200000;
- long now = System.currentTimeMillis();
- for (int j = 0; j < count; j++) {
- for (int i = 0; i < orderList.size(); i++) {
- Order order = orderList.get(i);
- String ret = execute(order, expression);
- if (!StringUtils.isEmpty(ret)) {
- order.setScore(Integer.valueOf(ret));
- }
-
- }
- }
- long cost = System.currentTimeMillis() - now;
- System.out.println("java程序执行:" + count + "次,耗时:" + cost + "ms");
- }
-
- public static String execute(Object obj, String expression) throws Exception {
- expressContext.put("o", obj);
- List<String> errorInfo = new ArrayList<String>();
- Object resultObj = runner.execute(expression, expressContext, errorInfo, true, false);
- return null == resultObj ? "" : resultObj.toString();
- }
-
-
- private static List<Order> getInitData() throws Exception {
- List<Order> orderList = new ArrayList<Order>();
- DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
- {
- Order order = new Order();
- order.setAmout(80);
- order.setBookingDate(df.parse("2015-07-01"));
- User user = new User();
- user.setLevel(1);
- user.setName("Name1");
- order.setUser(user);
- orderList.add(order);
- }
- {
- Order order = new Order();
- order.setAmout(200);
- order.setBookingDate(df.parse("2015-07-02"));
- User user = new User();
- user.setLevel(2);
- user.setName("Name2");
- order.setUser(user);
- orderList.add(order);
- }
- {
- Order order = new Order();
- order.setAmout(800);
- order.setBookingDate(df.parse("2015-07-03"));
- User user = new User();
- user.setLevel(3);
- user.setName("Name3");
- order.setUser(user);
- orderList.add(order);
- }
- {
- Order order = new Order();
- order.setAmout(1500);
- order.setBookingDate(df.parse("2015-07-04"));
- User user = new User();
- user.setLevel(4);
- user.setName("Name4");
- order.setUser(user);
- orderList.add(order);
- }
- return orderList;
- }
-
- }

pom.xml
- <dependency>
- <groupId>com.alibaba</groupId>
- <artifactId>fastjson</artifactId>
- <version>1.2.83</version>
- </dependency>
- <dependency>
- <groupId>com.alibaba</groupId>
- <artifactId>QLExpress</artifactId>
- <version>3.2.2</version>
- </dependency>
以上测试均在JDK1.8下完成
本文代码仓库: https://github.com/philip502/rule-engine-demo.git
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。