表達式引擎性能對比

1. 表達式引擎選型

如果要做一個規則引擎,需要匹配一組規則集來做決策,此時就需要一個表達式引擎來輔助。
選擇 5 種表達式引擎進行性能對比,從而選擇最優表達式引擎和最優方案。Janino、QLExpress、MEVL、JUEL、FEL。
當然,除了計算性能,還要考慮是否滿足功能,以及是否有安全漏洞等,本文僅進行表達式引擎的性能對比。

2. 性能測試

2.1 測試維度

  1. 表達式維度:主要採用了3種表達式,表達式的語法在不同的表達式引擎中也不同,詳見3.2 。
  • 表達式1: 最常見的場景(多個條件進行and操作):city.equals(‘杭州’) && age<=20
  • 表達式2: 包含特殊的操作(contains):city.equals(‘杭州’) && age<=20 && stringList.contains(str)
  • 表達式3: 一個稍微複雜一點的語法樹 :a>1 && ((b>1 || c<1) || (a>1 && b<1 && c>1))
  1. 數據量
  • 1000萬
  • 2000萬
  • 4000萬

2.2 測試方式

根據數據量執行多少次 for 循環,記錄下表達式計算的總耗時,單位毫秒 (ms)。爲了保證一定的差異性,變量賦值的時候,採用變化的值。代碼詳見 3.2 。

2.3 結論

  • 表達式1:city.equals(“杭州”) && age<=20
Janino QL Mvel (預編譯) Juel Fel
1000萬 583 6885 2634 3174 125065
2000萬 1171 11363 4167 4318 277257
4000萬 1951 22979 8544 9117 519036
  • 表達式2: city.equals(“杭州”) && age<=20 && stringList.contains(str)
Janino QL Mvel (預編譯) Juel Fel
1000萬 508 6473 2810 2787 166865
2000萬 983 12793 4627 5728 339085
4000萬 2008 25595 9656 11417 670728
  • 表達式3:a>1 && ((b>1 || c<1) || (a>1 && b<1 && c>1))
Janino QL Mvel (預編譯) Juel Fel
1000萬 489 3082 2206 3056 167739
2000萬 947 6156 3445 5950 321651
4000萬 1909 12353 7284 12934 642368

Janino 表達式引擎的性能最優。
處理速度上,Janino > Mvel(預編譯) > Juel > QL > Fel 。

3. 附錄

3.1 機器配置

本機 Mac 配置:
MacBook Pro (13-inch, 2019, Four Thunderbolt 3 ports)
處理器 2.4 GHz 四核Intel Core i5
內存 16 GB 2133 MHz LPDDR3
圖形卡 Intel Iris Plus Graphics 655 1536 MB

3.2 Java 測試代碼

  • Janino
import org.codehaus.commons.compiler.CompilerFactoryFactory;
import org.codehaus.commons.compiler.IExpressionEvaluator;
import org.junit.Test;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

/**
 * Description:
 *
 * @author mwt
 * @version 1.0
 * @date 2020/5/21
 */
public class JaninoExpressionTest {

    @Test
    public void test1() throws Exception {
        String ruleExpress = "city.equals(\"杭州\") && age<=20";

        long count1 = 1000 * 10000;
        System.out.println("\nJaninoExpression1 數據量 1000 萬:");
        execute(count1, ruleExpress);

        long count2 = 2000 * 10000;
        System.out.println("\nJaninoExpression1 數據量 2000 萬:");
        execute(count2, ruleExpress);

        long count3 = 4000 * 10000;
        System.out.println("\nJaninoExpression1 數據量 4000 萬:");
        execute(count3, ruleExpress);
    }


    @Test
    public void test2() throws Exception {
        String ruleExpress = "city.equals(\"杭州\") && age<=20 && stringList.contains(str)";

        long count1 = 1000 * 10000;
        System.out.println("\nJaninoExpression2 數據量 1000 萬:");
        execute(count1, ruleExpress);

        long count2 = 2000 * 10000;
        System.out.println("\nJaninoExpression2 數據量 2000 萬:");
        execute(count2, ruleExpress);

        long count3 = 4000 * 10000;
        System.out.println("\nJaninoExpression2 數據量 4000 萬:");
        execute(count3, ruleExpress);

    }

    @Test
    public void test3() throws Exception {
        String ruleExpress = "a>1 && ((b>1 || c<1) || (a>1 && b<1 && c>1))";

        long count1 = 1000 * 10000;
        System.out.println("\nJaninoExpression3 數據量 1000 萬:");
        execute(count1, ruleExpress);

        long count2 = 2000 * 10000;
        System.out.println("\nJaninoExpression3 數據量 2000 萬:");
        execute(count2, ruleExpress);

        long count3 = 4000 * 10000;
        System.out.println("\nJaninoExpression3 數據量 4000 萬:");
        execute(count3, ruleExpress);
    }

    private void execute(long count, String expression) throws Exception {
        IExpressionEvaluator expressionEvaluator =
                CompilerFactoryFactory.getDefaultCompilerFactory().newExpressionEvaluator();
        expressionEvaluator.setExpressionType(boolean.class);
        expressionEvaluator.setParameters(
                new String[]{"city", "age", "stringList", "str", "a", "b", "c"},
                new Class[]{String.class, Integer.class, List.class, String.class,
                        Integer.class, Integer.class, Integer.class}
        );
        expressionEvaluator.cook(expression);

        long start = System.currentTimeMillis();
        List<String> stringList = new ArrayList<String>(2);
        stringList.add("hello");
        stringList.add("world");
        Random random = new Random();
        for (int i = 0; i < count; i++) {
            Object[] arguments = new Object[7];
            int age = random.nextInt(50);
            if (i % 2 == 0) {
                arguments[0] = "杭州";
            } else {
                arguments[0] = "北京";

            }
            arguments[1] = age;
            arguments[2] = stringList;
            if (i % 3 == 0) {
                arguments[3] = "hello";
            } else if (i % 3 == 1) {
                arguments[3] = "world";
            } else {
                arguments[3] = "anything";
            }
            arguments[4] = random.nextInt(2);
            arguments[5] = random.nextInt(2);
            arguments[6] = random.nextInt(2);

            Object res = expressionEvaluator.evaluate(arguments);
        }
        long end = System.currentTimeMillis();
        long intervalInMs = end - start;
        float avg = (float) count / intervalInMs * 1000;

        System.out.println("總耗時毫秒:" + intervalInMs);
        System.out.println("每秒處理條數:" + avg);
    }
}
  • QL
import com.ql.util.express.DefaultContext;
import com.ql.util.express.ExpressRunner;
import org.junit.Test;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

/**
 * Description:
 *
 * @author mwt
 * @version 1.0
 * @date 2020/5/21
 */
public class QLExpressTest {

    @Test
    public void test1() throws Exception {
        String ruleExpress = "city.equals(\"杭州\") && age<=20";

        long count1 = 1000 * 10000;
        System.out.println("\nQLExpress1 數據量 1000 萬:");
        execute(count1, ruleExpress);

        long count2 = 2000 * 10000;
        System.out.println("\nQLExpress1 數據量 2000 萬:");
        execute(count2, ruleExpress);

        long count3 = 4000 * 10000;
        System.out.println("\nQLExpress1 數據量 4000 萬:");
        execute(count3, ruleExpress);
    }


    @Test
    public void test2() throws Exception {
        String ruleExpress = "city.equals(\"杭州\") && age<=20 && stringList.contains(str)";

        long count1 = 1000 * 10000;
        System.out.println("\nQLExpress2 數據量 1000 萬:");
        execute(count1, ruleExpress);

        long count2 = 2000 * 10000;
        System.out.println("\nQLExpress2 數據量 2000 萬:");
        execute(count2, ruleExpress);

        long count3 = 4000 * 10000;
        System.out.println("\nQLExpress2 數據量 4000 萬:");
        execute(count3, ruleExpress);

    }

    @Test
    public void test3() throws Exception {
        String ruleExpress = "a>1 && ((b>1 || c<1) || (a>1 && b<1 && c>1))";

        long count1 = 1000 * 10000;
        System.out.println("\nQLExpress3 數據量 1000 萬:");
        execute(count1, ruleExpress);

        long count2 = 2000 * 10000;
        System.out.println("\nQLExpress3 數據量 2000 萬:");
        execute(count2, ruleExpress);

        long count3 = 4000 * 10000;
        System.out.println("\nQLExpress3 數據量 4000 萬:");
        execute(count3, ruleExpress);
    }


    private void execute(long count, String expression) throws Exception {
        ExpressRunner runner = new ExpressRunner();
        DefaultContext<String, Object> context = new DefaultContext<String, Object>();

        long start = System.currentTimeMillis();
        List<String> stringList = new ArrayList<String>(2);
        stringList.add("hello");
        stringList.add("world");
        Random random = new Random();
        for (int i = 0; i < count; i++) {
            int age = random.nextInt(50);
            if (i % 2 == 0) {
                context.put("city", "杭州");
            } else {
                context.put("city", "北京");
            }
            context.put("age", age);
            context.put("stringList", stringList);
            if (i % 3 == 0) {
                context.put("str", "hello");
            } else if (i % 3 == 1) {
                context.put("str", "world");

            } else {
                context.put("str", "anything");
            }
            context.put("a",random.nextInt(2));
            context.put("b",random.nextInt(2));
            context.put("c",random.nextInt(2));

            Object res = runner.execute(expression, context, null, true, false);

        }
        long end = System.currentTimeMillis();
        long intervalInMs = end - start;
        float avg = (float) count / intervalInMs * 1000;

        System.out.println("總耗時毫秒:" + intervalInMs);
        System.out.println("每秒處理條數:" + avg);
    }
}
  • Mvel
import org.junit.Test;
import org.mvel2.MVEL;
import org.mvel2.ParserContext;

import java.io.Serializable;
import java.util.*;

/**
 * Description:
 *
 * @author mwt
 * @version 1.0
 * @date 2020/5/22
 */
public class MvelExpressTest {

    // =========================== mvel 不編譯,超級慢 ===========================
    @Test
    public void test11() {
        String ruleExpress = "city=='杭州' && age<=20";

        long count1 = 1000 * 10000;
        System.out.println("\nMvelCompileExpress1 數據量 1000 萬:");
        execute1(count1, ruleExpress);

        long count2 = 2000 * 10000;
        System.out.println("\nMvelCompileExpress1 數據量 2000 萬:");
        execute1(count2, ruleExpress);

        long count3 = 4000 * 10000;
        System.out.println("\nMvelCompileExpress1 數據量 4000 萬:");
        execute1(count3, ruleExpress);
    }


    @Test
    public void test12() {
        String ruleExpress = "city=='杭州' && age<=20 && stringList.contains(str)";

        long count1 = 1000 * 10000;
        System.out.println("\nMvelCompileExpress2 數據量 1000 萬:");
        execute1(count1, ruleExpress);

        long count2 = 2000 * 10000;
        System.out.println("\nMvelCompileExpress2 數據量 2000 萬:");
        execute1(count2, ruleExpress);

        long count3 = 4000 * 10000;
        System.out.println("\nMvelCompileExpress2 數據量 4000 萬:");
        execute1(count3, ruleExpress);

    }

    @Test
    public void test13() {
        String ruleExpress = "a>1 && ((b>1 || c<1) || (a>1 && b<1 && c>1))";

        long count1 = 1000 * 10000;
        System.out.println("\nMvelCompileExpress3 數據量 1000 萬:");
        execute1(count1, ruleExpress);

        long count2 = 2000 * 10000;
        System.out.println("\nMvelCompileExpress3 數據量 2000 萬:");
        execute1(count2, ruleExpress);

        long count3 = 4000 * 10000;
        System.out.println("\nMvelCompileExpress3 數據量 4000 萬:");
        execute1(count3, ruleExpress);
    }


    // =========================== mvel 先編譯 ===========================
    @Test
    public void test21() {
        String ruleExpress = "city=='杭州' && age<=20";

        long count1 = 1000 * 10000;
        System.out.println("\nMvelCompileExpress1 數據量 1000 萬:");
        execute2(count1, ruleExpress);

        long count2 = 2000 * 10000;
        System.out.println("\nMvelCompileExpress1 數據量 2000 萬:");
        execute2(count2, ruleExpress);

        long count3 = 4000 * 10000;
        System.out.println("\nMvelCompileExpress1 數據量 4000 萬:");
        execute2(count3, ruleExpress);
    }


    @Test
    public void test22() {
        String ruleExpress = "city=='杭州' && age<=20 && stringList.contains(str)";

        long count1 = 1000 * 10000;
        System.out.println("\nMvelCompileExpress2 數據量 1000 萬:");
        execute2(count1, ruleExpress);

        long count2 = 2000 * 10000;
        System.out.println("\nMvelCompileExpress2 數據量 2000 萬:");
        execute2(count2, ruleExpress);

        long count3 = 4000 * 10000;
        System.out.println("\nMvelCompileExpress2 數據量 4000 萬:");
        execute2(count3, ruleExpress);

    }

    @Test
    public void test23() {
        String ruleExpress = "a>1 && ((b>1 || c<1) || (a>1 && b<1 && c>1))";

        long count1 = 1000 * 10000;
        System.out.println("\nMvelCompileExpress3 數據量 1000 萬:");
        execute2(count1, ruleExpress);

        long count2 = 2000 * 10000;
        System.out.println("\nMvelCompileExpress3 數據量 2000 萬:");
        execute2(count2, ruleExpress);

        long count3 = 4000 * 10000;
        System.out.println("\nMvelCompileExpress3 數據量 4000 萬:");
        execute2(count3, ruleExpress);
    }

    // =========================== mvel 先編譯,且輸入值類型指定 ===========================
    @Test
    public void test31() {
        String ruleExpress = "city=='杭州' && age<=20";

        long count1 = 1000 * 10000;
        System.out.println("\nMvelCompileExpress1 數據量 1000 萬:");
        execute3(count1, ruleExpress);

        long count2 = 2000 * 10000;
        System.out.println("\nMvelCompileExpress1 數據量 2000 萬:");
        execute3(count2, ruleExpress);

        long count3 = 4000 * 10000;
        System.out.println("\nMvelCompileExpress1 數據量 4000 萬:");
        execute3(count3, ruleExpress);
    }


    @Test
    public void test32() {
        String ruleExpress = "city=='杭州' && age<=20 && stringList.contains(str)";

        long count1 = 1000 * 10000;
        System.out.println("\nMvelCompileExpress2 數據量 1000 萬:");
        execute3(count1, ruleExpress);

        long count2 = 2000 * 10000;
        System.out.println("\nMvelCompileExpress2 數據量 2000 萬:");
        execute3(count2, ruleExpress);

        long count3 = 4000 * 10000;
        System.out.println("\nMvelCompileExpress2 數據量 4000 萬:");
        execute3(count3, ruleExpress);

    }

    @Test
    public void test33() {
        String ruleExpress = "a>1 && ((b>1 || c<1) || (a>1 && b<1 && c>1))";

        long count1 = 1000 * 10000;
        System.out.println("\nMvelCompileExpress3 數據量 1000 萬:");
        execute3(count1, ruleExpress);

        long count2 = 2000 * 10000;
        System.out.println("\nMvelCompileExpress3 數據量 2000 萬:");
        execute3(count2, ruleExpress);

        long count3 = 4000 * 10000;
        System.out.println("\nMvelCompileExpress3 數據量 4000 萬:");
        execute3(count3, ruleExpress);
    }

    /**
     * mvel 不編譯
     */
    private void execute1(long count, String expression) {

        long start = System.currentTimeMillis();
        Map<String, Object> paramMap = new HashMap<String, Object>();
        List<String> stringList = new ArrayList<String>(2);
        stringList.add("hello");
        stringList.add("world");
        Random random = new Random();
        for (int i = 0; i < count; i++) {
            int age = random.nextInt(50);
            if (i % 2 == 0) {
                paramMap.put("city", "杭州");
            } else {
                paramMap.put("city", "北京");
            }
            paramMap.put("age", age);
            paramMap.put("stringList", stringList);
            if (i % 3 == 0) {
                paramMap.put("str", "hello");
            } else if (i % 3 == 1) {
                paramMap.put("str", "world");

            } else {
                paramMap.put("str", "anything");
            }
            paramMap.put("a", random.nextInt(2));
            paramMap.put("b", random.nextInt(2));
            paramMap.put("c", random.nextInt(2));

            Object res = MVEL.eval(expression, paramMap);

        }
        long end = System.currentTimeMillis();
        long intervalInMs = end - start;
        float avg = (float) count / intervalInMs * 1000;

        System.out.println("總耗時毫秒:" + intervalInMs);
        System.out.println("每秒處理條數:" + avg);
    }


    /**
     * mvel 先編譯
     */
    private void execute2(long count, String expression) {

        long start = System.currentTimeMillis();
        Serializable serializable = MVEL.compileExpression(expression);
        Map<String, Object> paramMap = new HashMap<String, Object>();
        List<String> stringList = new ArrayList<String>(2);
        stringList.add("hello");
        stringList.add("world");
        Random random = new Random();
        for (int i = 0; i < count; i++) {
            int age = random.nextInt(50);
            if (i % 2 == 0) {
                paramMap.put("city", "杭州");
            } else {
                paramMap.put("city", "北京");
            }
            paramMap.put("age", age);
            paramMap.put("stringList", stringList);
            if (i % 3 == 0) {
                paramMap.put("str", "hello");
            } else if (i % 3 == 1) {
                paramMap.put("str", "world");

            } else {
                paramMap.put("str", "anything");
            }
            paramMap.put("a", random.nextInt(2));
            paramMap.put("b", random.nextInt(2));
            paramMap.put("c", random.nextInt(2));

            Object res = MVEL.executeExpression(serializable, paramMap);

        }
        long end = System.currentTimeMillis();
        long intervalInMs = end - start;
        float avg = (float) count / intervalInMs * 1000;

        System.out.println("總耗時毫秒:" + intervalInMs);
        System.out.println("每秒處理條數:" + avg);
    }

    /**
     * mvel 先編譯,且輸入值類型指定
     */
    private void execute3(long count, String expression) {

        long start = System.currentTimeMillis();
        ParserContext context = ParserContext.create();
        context.addInput("city", String.class);
        context.addInput("age", Integer.class);
        context.addInput("stringList", List.class);
        context.addInput("str", String.class);
        context.addInput("a", Integer.class);
        context.addInput("b", Integer.class);
        context.addInput("c", Integer.class);

        Serializable serializable = MVEL.compileExpression(expression);
        Map<String, Object> paramMap = new HashMap<String, Object>();
        List<String> stringList = new ArrayList<String>(2);
        stringList.add("hello");
        stringList.add("world");
        Random random = new Random();
        for (int i = 0; i < count; i++) {
            int age = random.nextInt(50);
            if (i % 2 == 0) {
                paramMap.put("city", "杭州");
            } else {
                paramMap.put("city", "北京");
            }
            paramMap.put("age", age);
            paramMap.put("stringList", stringList);
            if (i % 3 == 0) {
                paramMap.put("str", "hello");
            } else if (i % 3 == 1) {
                paramMap.put("str", "world");

            } else {
                paramMap.put("str", "anything");
            }
            paramMap.put("a", random.nextInt(2));
            paramMap.put("b", random.nextInt(2));
            paramMap.put("c", random.nextInt(2));

            Object res = MVEL.executeExpression(serializable, paramMap);

        }
        long end = System.currentTimeMillis();
        long intervalInMs = end - start;
        float avg = (float) count / intervalInMs * 1000;

        System.out.println("總耗時毫秒:" + intervalInMs);
        System.out.println("每秒處理條數:" + avg);
    }
}
  • Juel
import de.odysseus.el.ExpressionFactoryImpl;
import de.odysseus.el.util.SimpleContext;
import org.junit.Test;

import javax.el.ExpressionFactory;
import javax.el.ValueExpression;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

/**
 * Description:
 *
 * @author mwt
 * @version 1.0
 * @date 2020/5/22
 */
public class JuelExpressTest {

    @Test
    public void test1()   {
        String ruleExpress = "city.equals(\"杭州\") && age<=20";

        long count1 = 1000 * 10000;
        System.out.println("\nJuelExpress1 數據量 1000 萬:");
        execute(count1, ruleExpress);

        long count2 = 2000 * 10000;
        System.out.println("\nJuelExpress1 數據量 2000 萬:");
        execute(count2, ruleExpress);

        long count3 = 4000 * 10000;
        System.out.println("\nJuelExpress1 數據量 4000 萬:");
        execute(count3, ruleExpress);
    }


    @Test
    public void test2()   {
        String ruleExpress = "city.equals(\"杭州\") && age<=20 && stringList.contains(str)";

        long count1 = 1000 * 10000;
        System.out.println("\nJuelExpress2 數據量 1000 萬:");
        execute(count1, ruleExpress);

        long count2 = 2000 * 10000;
        System.out.println("\nJuelExpress2 數據量 2000 萬:");
        execute(count2, ruleExpress);

        long count3 = 4000 * 10000;
        System.out.println("\nJuelExpress2 數據量 4000 萬:");
        execute(count3, ruleExpress);

    }

    @Test
    public void test3()   {
        String ruleExpress = "a>1 && ((b>1 || c<1) || (a>1 && b<1 && c>1))";

        long count1 = 1000 * 10000;
        System.out.println("\nJuelExpress3 數據量 1000 萬:");
        execute(count1, ruleExpress);

        long count2 = 2000 * 10000;
        System.out.println("\nJuelExpress3 數據量 2000 萬:");
        execute(count2, ruleExpress);

        long count3 = 4000 * 10000;
        System.out.println("\nJuelExpress3 數據量 4000 萬:");
        execute(count3, ruleExpress);
    }


    private void execute(long count, String expression)  {

        ExpressionFactory factory = new ExpressionFactoryImpl();
        long start = System.currentTimeMillis();
        List<String> stringList = new ArrayList<String>(2);
        stringList.add("hello");
        stringList.add("world");
        Random random = new Random();
        for (int i = 0; i < count; i++) {
            SimpleContext context = new SimpleContext();

            int age = random.nextInt(50);
            if (i % 2 == 0) {
                context.setVariable("city", factory.createValueExpression("杭州", String.class));
            } else {
                context.setVariable("city", factory.createValueExpression("北京", String.class));
            }
            context.setVariable("age", factory.createValueExpression(age, Integer.class));
            context.setVariable("stringList", factory.createValueExpression(stringList, List.class));

            if (i % 3 == 0) {
                context.setVariable("str", factory.createValueExpression("hello", String.class));
            } else if (i % 3 == 1) {
                context.setVariable("str", factory.createValueExpression("world", String.class));
            } else {
                context.setVariable("str", factory.createValueExpression("anything", String.class));
            }
            context.setVariable("a", factory.createValueExpression(random.nextInt(2), Integer.class));
            context.setVariable("b", factory.createValueExpression(random.nextInt(2), Integer.class));
            context.setVariable("c", factory.createValueExpression(random.nextInt(2), Integer.class));

            ValueExpression e = factory.createValueExpression(context, "${" + expression + "}", Boolean.class);

        }
        long end = System.currentTimeMillis();
        long intervalInMs = end - start;
        float avg = (float) count / intervalInMs * 1000;

        System.out.println("總耗時毫秒:" + intervalInMs);
        System.out.println("每秒處理條數:" + avg);
    }
}
  • Fel
import com.greenpineyu.fel.FelEngine;
import com.greenpineyu.fel.FelEngineImpl;
import com.greenpineyu.fel.context.FelContext;
import org.junit.Test;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

/**
 * Description:
 *
 * @author mwt
 * @version 1.0
 * @date 2020/5/22
 */
public class FelExpressTest {

    @Test
    public void test1() {
        String ruleExpress = "city.equals(\"杭州\") && age<=20";

        long count1 = 1000 * 10000;
        System.out.println("\nFelExpress1 數據量 1000 萬:");
        execute(count1, ruleExpress);

        long count2 = 2000 * 10000;
        System.out.println("\nFelExpress1 數據量 2000 萬:");
        execute(count2, ruleExpress);

        long count3 = 4000 * 10000;
        System.out.println("\nFelExpress1 數據量 4000 萬:");
        execute(count3, ruleExpress);
    }


    @Test
    public void test2() {
        String ruleExpress = "city.equals(\"杭州\") && age<=20 && stringList.contains(str)";

        long count1 = 1000 * 10000;
        System.out.println("\nFelExpress2 數據量 1000 萬:");
        execute(count1, ruleExpress);

        long count2 = 2000 * 10000;
        System.out.println("\nFelExpress2 數據量 2000 萬:");
        execute(count2, ruleExpress);

        long count3 = 4000 * 10000;
        System.out.println("\nFelExpress2 數據量 4000 萬:");
        execute(count3, ruleExpress);

    }

    @Test
    public void test3() {
        String ruleExpress = "a>1 && ((b>1 || c<1) || (a>1 && b<1 && c>1))";

        long count1 = 1000 * 10000;
        System.out.println("\nFelExpress3 數據量 1000 萬:");
        execute(count1, ruleExpress);

        long count2 = 2000 * 10000;
        System.out.println("\nFelExpress3 數據量 2000 萬:");
        execute(count2, ruleExpress);

        long count3 = 4000 * 10000;
        System.out.println("\nFelExpress3 數據量 4000 萬:");
        execute(count3, ruleExpress);
    }


    private void execute(long count, String expression) {

        FelEngine fel = new FelEngineImpl();
        FelContext context = fel.getContext();

        long start = System.currentTimeMillis();
        List<String> stringList = new ArrayList<String>(2);
        stringList.add("hello");
        stringList.add("world");
        Random random = new Random();
        for (int i = 0; i < count; i++) {
            int age = random.nextInt(50);
            if (i % 2 == 0) {
                context.set("city", "杭州");
            } else {
                context.set("city", "北京");
            }
            context.set("age", age);
            context.set("stringList", stringList);
            if (i % 3 == 0) {
                context.set("str", "hello");
            } else if (i % 3 == 1) {
                context.set("str", "world");

            } else {
                context.set("str", "anything");
            }
            context.set("a", random.nextInt(2));
            context.set("b", random.nextInt(2));
            context.set("c", random.nextInt(2));

            Object res = fel.eval(expression, context);
            System.out.println(res);

        }
        long end = System.currentTimeMillis();
        long intervalInMs = end - start;
        float avg = (float) count / intervalInMs * 1000;

        System.out.println("總耗時毫秒:" + intervalInMs);
        System.out.println("每秒處理條數:" + avg);
    }
}

參考:
http://www.datadriven.top/2018/02/03/%E8%A1%A8%E8%BE%BE%E5%BC%8F%E5%BC%95%E6%93%8E%E6%80%A7%E8%83%BD%E6%AF%94%E8%BE%83/index.html
http://www.welkinbai.com/2019/05/30/ql-intro/#1-%E4%BE%9D%E8%B5%96%E5%92%8C%E5%9F%BA%E6%9C%AC%E8%B0%83%E7%94%A8-1
https://bigjun2017.github.io/2018/09/18/hou-duan/java/mvel2.x-yu-fa-zhi-nan/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章