Fel的介绍和简单使用以及0.9版本的包在之前的博客写过了,有需要的朋友移步:fel的简单使用及介绍
项目地址:https://github.com/an-yusheng/CSDN-FelDemo
1. 基础的应用
下面的代码是引用原生类进行执行的,支持通用数学函数即加减乘除
package com.example.demo.util;import com.greenpineyu.fel.FelEngine;
import com.greenpineyu.fel.FelEngineImpl;/*** @author Anzepeng* @title: FelDemo* @projectName demo* @description: TODO* @date 2020/6/3 0003下午 13:42*/
public class FelDemo {public static void main(String[] args){// 计算核心类FelEngine felEngine = new FelEngineImpl();// 执行计算的方法eval(公式)Object result = felEngine.eval("1+1");// 结果System.out.println("计算结果为:"+result);}
}
执行结果
如果仅仅是普通运算那并不能满足我们的需求,尝试一下聚合函数
错误信息找不到函数,原生包并没有支持这些函数,所以我们要重写它的实现代码
2. 查看源代码
FelEngineImpl的源代码
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//package com.greenpineyu.fel;import com.greenpineyu.fel.common.FelBuilder;
import com.greenpineyu.fel.compile.CompileService;
import com.greenpineyu.fel.context.ArrayCtxImpl;
import com.greenpineyu.fel.context.FelContext;
import com.greenpineyu.fel.context.Var;
import com.greenpineyu.fel.function.FunMgr;
import com.greenpineyu.fel.function.Function;
import com.greenpineyu.fel.optimizer.Optimizer;
import com.greenpineyu.fel.optimizer.VarVisitOpti;
import com.greenpineyu.fel.parser.AntlrParser;
import com.greenpineyu.fel.parser.FelNode;
import com.greenpineyu.fel.parser.Parser;
import com.greenpineyu.fel.security.SecurityMgr;public class FelEngineImpl implements FelEngine {private FelContext context;private CompileService compiler;private Parser parser;private FunMgr funMgr;private SecurityMgr securityMgr;public SecurityMgr getSecurityMgr() {return this.securityMgr;}public void setSecurityMgr(SecurityMgr var1) {this.securityMgr = var1;}public FelEngineImpl(FelContext var1) {this.securityMgr = FelBuilder.newSecurityMgr();this.context = var1;this.compiler = new CompileService();this.parser = new AntlrParser(this);this.funMgr = new FunMgr();}public FelEngineImpl() {this(new ArrayCtxImpl());}public FelNode parse(String var1) {return this.parser.parse(var1);}public Object eval(String var1) {return this.eval(var1, this.context);}public Object eval(String var1, Var... var2) {FelNode var3 = this.parse(var1);VarVisitOpti var4 = new VarVisitOpti(var2);var3 = var4.call(this.context, var3);return var3.eval(this.context);}public Object eval(String var1, FelContext var2) {return this.parse(var1).eval(var2);}public Expression compile(String var1, Var... var2) {return this.compile(var1, (FelContext)null, new VarVisitOpti(var2));}public Expression compile(String var1, FelContext var2, Optimizer... var3) {if (var2 == null) {var2 = this.context;}FelNode var4 = this.parse(var1);if (var3 != null) {Optimizer[] var5 = var3;int var6 = var3.length;for(int var7 = 0; var7 < var6; ++var7) {Optimizer var8 = var5[var7];if (var8 != null) {var4 = var8.call(var2, var4);}}}return this.compiler.compile(var2, var4, var1);}public String toString() {return "FelEngine";}public void addFun(Function var1) {this.funMgr.add(var1);}public FelContext getContext() {return this.context;}public CompileService getCompiler() {return this.compiler;}public void setCompiler(CompileService var1) {this.compiler = var1;}public Parser getParser() {return this.parser;}public void setParser(Parser var1) {this.parser = var1;}public FunMgr getFunMgr() {return this.funMgr;}public void setFunMgr(FunMgr var1) {this.funMgr = var1;}public void setContext(FelContext var1) {this.context = var1;}
}
3. 重写FelEngineImpl类并实现FelEngine
下面是我们创建可修改的实现类,跟源代码不一致的地方是我将 this(new ArrayCtxImpl()); 注释了
package com.example.demo.util;import com.greenpineyu.fel.Expression;
import com.greenpineyu.fel.FelEngine;
import com.greenpineyu.fel.common.FelBuilder;
import com.greenpineyu.fel.compile.CompileService;
import com.greenpineyu.fel.context.ArrayCtxImpl;
import com.greenpineyu.fel.context.FelContext;
import com.greenpineyu.fel.context.Var;
import com.greenpineyu.fel.function.FunMgr;
import com.greenpineyu.fel.function.Function;
import com.greenpineyu.fel.optimizer.Optimizer;
import com.greenpineyu.fel.optimizer.VarVisitOpti;
import com.greenpineyu.fel.parser.AntlrParser;
import com.greenpineyu.fel.parser.FelNode;
import com.greenpineyu.fel.parser.Parser;
import com.greenpineyu.fel.security.SecurityMgr;/*** @author Anzepeng* @title: FelEngineImpl* @projectName calculate* @description: TODO* @date 2020/5/20 0020下午 17:44*/
public class FelEngineImpl implements FelEngine {private FelContext context;private CompileService compiler;private Parser parser;private FunMgr funMgr;private SecurityMgr securityMgr;public SecurityMgr getSecurityMgr() {return this.securityMgr;}public void setSecurityMgr(SecurityMgr var1) {this.securityMgr = var1;}public FelEngineImpl(FelContext var1) {this.securityMgr = FelBuilder.newSecurityMgr();this.context = var1;this.compiler = new CompileService();this.parser = new AntlrParser(this);this.funMgr = new FunMgr();}public FelEngineImpl() {//this(new ArrayCtxImpl());}public FelNode parse(String var1) {return this.parser.parse(var1);}public Object eval(String var1) {return this.eval(var1, this.context);}public Object eval(String var1, Var... var2) {FelNode var3 = this.parse(var1);VarVisitOpti var4 = new VarVisitOpti(var2);var3 = var4.call(this.context, var3);return var3.eval(this.context);}public Object eval(String var1, FelContext var2) {return this.parse(var1).eval(var2);}public Expression compile(String var1, Var... var2) {return this.compile(var1, (FelContext)null, new VarVisitOpti(var2));}public Expression compile(String var1, FelContext var2, Optimizer... var3) {if (var2 == null) {var2 = this.context;}FelNode var4 = this.parse(var1);if (var3 != null) {Optimizer[] var5 = var3;int var6 = var3.length;for(int var7 = 0; var7 < var6; ++var7) {Optimizer var8 = var5[var7];if (var8 != null) {var4 = var8.call(var2, var4);}}}return this.compiler.compile(var2, var4, var1);}public String toString() {return "FelEngine";}public void addFun(Function var1) {this.funMgr.add(var1);}public FelContext getContext() {return this.context;}public CompileService getCompiler() {return this.compiler;}public void setCompiler(CompileService var1) {this.compiler = var1;}public Parser getParser() {return this.parser;}public void setParser(Parser var1) {this.parser = var1;}public FunMgr getFunMgr() {return this.funMgr;}public void setFunMgr(FunMgr var1) {this.funMgr = var1;}public void setContext(FelContext var1) {this.context = var1;}
}
在demo类里将引用的FelEngineImpl类改成我们创建的这个然后执行
出现错误java.lang.NullPointerException
解开注释再次执行,恢复正常
这个方法里写的就是我们定义好的运算,函数或方法,Parser解析公式后执行的运算就是匹配这个方法里的内容
4. 编写自定义函数
在上面知道运算方法后我们就要加入自定义函数了,fel的简单使用及介绍 里面也讲过自定义函数了,我们直接拿过来修改一下
我们只取第一部分代码并修改一下,改成sum的函数,并添加函数引用,代码如下
public FelEngineImpl() {this(new ArrayCtxImpl());// sum函数Function sumFun = new CommonFunction() {public String getName() {return "sum";}@Overridepublic Object call(Object... values) {Double sum=0d;for(Object o:values){if(o!=null){Double d= NumberUtil.toDouble(o);sum+=d;}}return sum;}};// 添加sum函数this.addFun(sumFun);}
修改完成,执行一下sum函数
5. 重写后的FelEngineImpl代码执行示例
支持的运算 、函数、判断
普通运算:加减乘除
聚合函数:MAX、MIN、AVG、SUM、、、等
关系:大于、小于、大于等于、小于等于、等于、不等于等
条件:?:
6. 百万数据速度测试
因为输出所有结果会影响真实速度,我们先不输出测试一下
百万数据计算速度10161ms,平均每秒10w,我们再输出一下公式结果,确定一下计算结果正确性
结果应该没有错误,因为有输出所以多了8s的时间
7. FelEngineImpl代码
package com.example.demo.util;import com.greenpineyu.fel.Expression;
import com.greenpineyu.fel.FelEngine;
import com.greenpineyu.fel.common.FelBuilder;
import com.greenpineyu.fel.common.NumberUtil;
import com.greenpineyu.fel.common.ObjectUtils;
import com.greenpineyu.fel.compile.CompileService;
import com.greenpineyu.fel.context.ArrayCtxImpl;
import com.greenpineyu.fel.context.FelContext;
import com.greenpineyu.fel.context.Var;
import com.greenpineyu.fel.function.CommonFunction;
import com.greenpineyu.fel.function.FunMgr;
import com.greenpineyu.fel.function.Function;
import com.greenpineyu.fel.optimizer.Optimizer;
import com.greenpineyu.fel.optimizer.VarVisitOpti;
import com.greenpineyu.fel.parser.AntlrParser;
import com.greenpineyu.fel.parser.FelNode;
import com.greenpineyu.fel.parser.Parser;
import com.greenpineyu.fel.security.SecurityMgr;import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Random;/*** @author Anzepeng* @title: FelEngineImpl* @projectName calculate* @description: TODO* @date 2020/5/20 0020下午 17:44*/
public class FelEngineImpl implements FelEngine {private FelContext context;private CompileService compiler;private Parser parser;private FunMgr funMgr;private SecurityMgr securityMgr;public SecurityMgr getSecurityMgr() {return this.securityMgr;}public void setSecurityMgr(SecurityMgr var1) {this.securityMgr = var1;}public FelEngineImpl(FelContext var1) {this.securityMgr = FelBuilder.newSecurityMgr();this.context = var1;this.compiler = new CompileService();this.parser = new AntlrParser(this);this.funMgr = new FunMgr();}public FelEngineImpl() {this(new ArrayCtxImpl());Function funmax= new CommonFunction() {public String getName() {return "MAX";}@Overridepublic Object call(Object... values) {Double max=0-Double.MAX_VALUE;for(Object o:values){Double d=NumberUtil.toDouble(o);if(d.compareTo(max)>0){max=d;}}return max;}};this.addFun(funmax);Function funmin= new CommonFunction() {public String getName() {return "MIN";}@Overridepublic Object call(Object... values) {Double min=Double.MAX_VALUE;for(Object o:values){Double d=NumberUtil.toDouble(o);if(d.compareTo(min)<0){min=d;}}return min;}};this.addFun(funmin);Function funavg= new CommonFunction() {public String getName() {return "AVG";}@Overridepublic Object call(Object... values) {Double sum=0d;for(Object o:values){Double d=NumberUtil.toDouble(o);sum+=d;}return sum/values.length;}};this.addFun(funavg);Function avgeli= new CommonFunction() {public String getName() {return "AVGELI";}@Overridepublic Object call(Object... values) {Double sum=0d;int count=0;for(Object o:values){if(o!=null){Double d=NumberUtil.toDouble(o);sum+=d;if(d!=0.0){count++;}}}return sum/count;}};this.addFun(avgeli);Function funsum= new CommonFunction() {public String getName() {return "SUM";}@Overridepublic Object call(Object... values) {Double sum=0d;for(Object o:values){if(o!=null){Double d=NumberUtil.toDouble(o);sum+=d;}}return sum;}};this.addFun(funsum);Function funabs= new CommonFunction() {public String getName() {return "ABS";}@Overridepublic Object call(Object... values) {Double result=NumberUtil.toDouble(values[0]);return Math.abs(result);}};this.addFun(funabs);Function funbadmin= new CommonFunction() {public String getName() {return "BADMIN";}@Overridepublic Object call(Object... values) {Double min=Double.MAX_VALUE;boolean a=true;for(Object o:values){Double d=NumberUtil.toDouble(o);Double b=Math.abs(d);if(b.compareTo(min)<0){min=b;if(d>=0){a=true;}else{a=false;}}}if(a){return min;}else{return 0-min;}}};this.addFun(funbadmin);Function funbadmax= new CommonFunction() {public String getName() {return "BADMAX";}@Overridepublic Object call(Object... values) {Double max=0d;boolean a=true;for(Object o:values){Double d=NumberUtil.toDouble(o);if(d.equals(NumberUtil.toDouble(-100))){continue;}Double b=Math.abs(d);if(b.compareTo(max)>0){if(d>=0){a=true;}else{a=false;}max=b;}}if(a){return max;}else{return 0-max;}}};this.addFun(funbadmax);Function funacos= new CommonFunction() {public String getName() {return "ACOS";}@Overridepublic Object call(Object... values) {Double result=NumberUtil.toDouble(values[0]);return Math.acos(result);}};this.addFun(funacos);Function funasin= new CommonFunction() {public String getName() {return "ASIN";}@Overridepublic Object call(Object... values) {Double result=NumberUtil.toDouble(values[0]);return Math.asin(result);}};this.addFun(funasin);Function funatan= new CommonFunction() {public String getName() {return "ATAN";}@Overridepublic Object call(Object... values) {Double result=NumberUtil.toDouble(values[0]);return Math.atan(result);}};this.addFun(funatan);Function funcos= new CommonFunction() {public String getName() {return "COS";}@Overridepublic Object call(Object... values) {Double result=NumberUtil.toDouble(values[0]);return Math.cos(result);}};this.addFun(funcos);Function funsin= new CommonFunction() {public String getName() {return "SIN";}@Overridepublic Object call(Object... values) {Double result=NumberUtil.toDouble(values[0]);return Math.sin(result);}};this.addFun(funsin);Function funtan= new CommonFunction() {public String getName() {return "TAN";}@Overridepublic Object call(Object... values) {Double result=NumberUtil.toDouble(values[0]);return Math.tan(result);}};this.addFun(funtan);Function funceil= new CommonFunction() {public String getName() {return "CEIL";}@Overridepublic Object call(Object... values) {Double result=NumberUtil.toDouble(values[0]);return Math.ceil(result);}};this.addFun(funceil);Function funround= new CommonFunction() {public String getName() {return "ROUND";}@Overridepublic Object call(Object... values) {Double result=NumberUtil.toDouble(values[0]);return Math.round(result*100)*0.01;}};this.addFun(funround);Function funfloor= new CommonFunction() {public String getName() {return "FLOOR";}@Overridepublic Object call(Object... values) {Double result=NumberUtil.toDouble(values[0]);return Math.floor(result);}};this.addFun(funfloor);Function funsqrt= new CommonFunction() {public String getName() {return "SQRT";}@Overridepublic Object call(Object... values) {Double result=NumberUtil.toDouble(values[0]);return Math.sqrt(result);}};this.addFun(funsqrt);Function funpow= new CommonFunction() {public String getName() {return "POW";}@Overridepublic Object call(Object... values) {Double arg1=NumberUtil.toDouble(values[0]);return Math.pow(arg1,2);}};this.addFun(funpow);Function funpown= new CommonFunction() {public String getName() {return "POWN";}@Overridepublic Object call(Object... values) {Double arg1=NumberUtil.toDouble(values[0]);Double arg2=NumberUtil.toDouble(values[1]);return Math.pow(arg1,arg2);}};this.addFun(funpown);Function funsqrtn= new CommonFunction() {public String getName() {return "SQRTN";}@Overridepublic Object call(Object... values) {Double arg1=NumberUtil.toDouble(values[0]);Double arg2=NumberUtil.toDouble(values[1]);return Math.pow(arg1,1/arg2);}};this.addFun(funsqrtn);Function equals= new CommonFunction() {public String getName() {return "EQUALS";}@Overridepublic Object call(Object... values) {return values[0].equals(values[1]);}};this.addFun(equals);Function isnull= new CommonFunction() {public String getName() {return "ISNULL";}@Overridepublic Object call(Object... values) {if(values==null||values[0]==null||"".equals(values[0].toString().trim())){return true;}return false;}};this.addFun(isnull);Function nulltozero= new CommonFunction() {public String getName() {return "NULLTOZERO";}@Overridepublic Object call(Object... values) {if(values==null||values[0]==null||"".equals(values[0].toString().trim())){return 0;}return values[0];}};this.addFun(nulltozero);Function concat= new CommonFunction() {public String getName() {return "CONCAT";}@Overridepublic Object call(Object... values) {StringBuffer result=new StringBuffer();for(Object v:values){if(v!=null)result.append(v);}return result.toString();}};this.addFun(concat);Function date= new CommonFunction() {public String getName() {return "DATE";}@Overridepublic Object call(Object... values) {SimpleDateFormat format=null;if(values==null){format=new SimpleDateFormat("yyyy-MM-dd");} else if(values[0].toString().equals("1")){format=new SimpleDateFormat("yyyy-MM-dd-");} else if(values[0].toString().equals("2")){format=new SimpleDateFormat("yyyy-MM");} else if(values[0].toString().equals("3")){format=new SimpleDateFormat("yyyy");}return format.format(new Date(System.currentTimeMillis()));}};this.addFun(date);Function random= new CommonFunction() {public String getName() {return "RANDOM";}@Overridepublic Object call(Object... values) {Random random1 = new Random(System.currentTimeMillis());int a=random1.nextInt(2);Double c=Double.valueOf(values[0].toString());double b = random1.nextInt((int)(c*Double.valueOf(values[1].toString())*10000))/1000000.0;if(a==1){return c+b;}else{return c-b;}}};this.addFun(random);Function predate= new CommonFunction() {public String getName() {return "PREDATE";}@Overridepublic Object call(Object... values) {SimpleDateFormat format=null;Calendar calendar=Calendar.getInstance();calendar.setFirstDayOfWeek(2);if(values==null){calendar.add(Calendar.DAY_OF_YEAR, -1);format=new SimpleDateFormat("yyyy-MM-dd");} else if(values[0].toString().equals("1")){calendar.add(Calendar.DAY_OF_YEAR, -1);format=new SimpleDateFormat("yyyy-MM-dd");} else if(values[0].toString().equals("2")){calendar.add(Calendar.MONTH, -1);format=new SimpleDateFormat("yyyy-MM");} else if(values[0].toString().equals("3")){calendar.add(Calendar.YEAR, -1);format=new SimpleDateFormat("yyyy");}return format.format(calendar.getTime());}};this.addFun(predate);Function pre15time= new CommonFunction() {public String getName() {return "PRE15TIME";}@Overridepublic Object call(Object... values) {SimpleDateFormat format=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");Calendar calendar=Calendar.getInstance();if(values!=null){calendar.setTime(new Date((Long)values[0]));}calendar.setFirstDayOfWeek(2);int minu=calendar.get(Calendar.MINUTE);if(minu%15!=0){minu=((int)(minu/15))*15;}calendar.set(Calendar.SECOND, 0);calendar.set(Calendar.MINUTE, minu);return format.format(calendar.getTime());}};this.addFun(pre15time);}public FelNode parse(String var1) {return this.parser.parse(var1);}public Object eval(String var1) {return this.eval(var1, this.context);}public Object eval(String var1, Var... var2) {FelNode var3 = this.parse(var1);VarVisitOpti var4 = new VarVisitOpti(var2);var3 = var4.call(this.context, var3);return var3.eval(this.context);}public Object eval(String var1, FelContext var2) {return this.parse(var1).eval(var2);}public Expression compile(String var1, Var... var2) {return this.compile(var1, (FelContext)null, new VarVisitOpti(var2));}public Expression compile(String var1, FelContext var2, Optimizer... var3) {if (var2 == null) {var2 = this.context;}FelNode var4 = this.parse(var1);if (var3 != null) {Optimizer[] var5 = var3;int var6 = var3.length;for(int var7 = 0; var7 < var6; ++var7) {Optimizer var8 = var5[var7];if (var8 != null) {var4 = var8.call(var2, var4);}}}return this.compiler.compile(var2, var4, var1);}public String toString() {return "FelEngine";}public void addFun(Function var1) {this.funMgr.add(var1);}public FelContext getContext() {return this.context;}public CompileService getCompiler() {return this.compiler;}public void setCompiler(CompileService var1) {this.compiler = var1;}public Parser getParser() {return this.parser;}public void setParser(Parser var1) {this.parser = var1;}public FunMgr getFunMgr() {return this.funMgr;}public void setFunMgr(FunMgr var1) {this.funMgr = var1;}public void setContext(FelContext var1) {this.context = var1;}
}