Aviator表达式引擎自定义可变参数函数

Aviator表达式引擎自定义可变参数函数

背景

离线任务需要按表达式计算数值,需要用到求平均值Avg或统计Sum,参数可变,支持嵌套。类似以下表达式:

avg(a+b,b,sum(b,c),avg(d,e))+2

之前使用Aviator作为规则引擎来使用,轻量化和性能都能满足于是想到了使用Aviator来实现此业务。

尝试

于是看了下之前写的Aviator自定义函数,和查了一些网上的文章都是通过继承 AbstractFunction 类来实现的:

public class TestAviator {
    public static void main(String[] args) {
            // 注册函数
            AviatorEvaluator.addFunction(new AddFunction());
            // 执行表达式
            Double result =  (Double)AviatorEvaluator.execute("add(1.5, 2)")
            System.out.println(result );
        }
    }
    class AddFunction extends AbstractFunction {
        @Override
        public AviatorObject call(Map<String, Object> env, 
                                  AviatorObject arg1, AviatorObject arg2) {
            Number num1 = FunctionUtils.getNumberValue(arg1, env);
            Number num2 = FunctionUtils.getNumberValue(arg2, env);
            return new AviatorDouble(num1.doubleValue() + num2 .doubleValue());
        }

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

通过代码可以看出继承 AbstractFunction 类后实现了 getName()call() 方法, getName() 定义了函数名,call() 用来实现函数逻辑,看了AbstractFunction 类里call() 方法的参数瞬间崩溃,方法参数 AviatorObject arg1 从1到20,难道就不支持可变参数吗?

public abstract class AbstractFunction extends AviatorObject implements AviatorFunction {
  private static final long serialVersionUID = -2391067902827877479L;

  @Override
  public AviatorObject call() throws Exception {
    return this.call(Env.EMPTY_ENV);
  }

  @Override
  public void run() {
    this.call(Env.EMPTY_ENV);
  }

  public AviatorObject throwArity(final int n) {
    String name = getName();
    throw new IllegalArgumentException("Wrong number of args (" + n + ") passed to: " + name);
  }

  @Override
  public String desc(final Map<String, Object> env) {
    return "<" + getAviatorType() + ", " + getName() + ">";
  }

  @Override
  public AviatorObject call(final Map<String, Object> env) {
    return throwArity(0);
  }


  @Override
  public int innerCompare(final AviatorObject other, final Map<String, Object> env) {
    throw new CompareNotSupportedException("Lambda function can't be compared.");
  }


  @Override
  public AviatorType getAviatorType() {
    return AviatorType.Lambda;
  }

  @Override
  public Object getValue(final Map<String, Object> env) {
    return this;
  }

  @Override
  public AviatorObject call(final Map<String, Object> env, final AviatorObject arg1) {
    return throwArity(1);
  }


  @Override
  public AviatorObject call(final Map<String, Object> env, final AviatorObject arg1,
      final AviatorObject arg2) {
    return throwArity(2);
  }


  @Override
  public AviatorObject call(final Map<String, Object> env, final AviatorObject arg1,
      final AviatorObject arg2, final AviatorObject arg3) {
    return throwArity(3);
  }


  @Override
  public AviatorObject call(final Map<String, Object> env, final AviatorObject arg1,
      final AviatorObject arg2, final AviatorObject arg3, final AviatorObject arg4) {
    return throwArity(4);
  }


  @Override
  public AviatorObject call(final Map<String, Object> env, final AviatorObject arg1,
      final AviatorObject arg2, final AviatorObject arg3, final AviatorObject arg4,
      final AviatorObject arg5) {
    return throwArity(5);
  }


  @Override
  public AviatorObject call(final Map<String, Object> env, final AviatorObject arg1,
      final AviatorObject arg2, final AviatorObject arg3, final AviatorObject arg4,
      final AviatorObject arg5, final AviatorObject arg6) {
    return throwArity(6);
  }


  @Override
  public AviatorObject call(final Map<String, Object> env, final AviatorObject arg1,
      final AviatorObject arg2, final AviatorObject arg3, final AviatorObject arg4,
      final AviatorObject arg5, final AviatorObject arg6, final AviatorObject arg7) {
    return throwArity(7);
  }


  @Override
  public AviatorObject call(final Map<String, Object> env, final AviatorObject arg1,
      final AviatorObject arg2, final AviatorObject arg3, final AviatorObject arg4,
      final AviatorObject arg5, final AviatorObject arg6, final AviatorObject arg7,
      final AviatorObject arg8) {
    return throwArity(8);
  }


  @Override
  public AviatorObject call(final Map<String, Object> env, final AviatorObject arg1,
      final AviatorObject arg2, final AviatorObject arg3, final AviatorObject arg4,
      final AviatorObject arg5, final AviatorObject arg6, final AviatorObject arg7,
      final AviatorObject arg8, final AviatorObject arg9) {
    return throwArity(9);
  }


  @Override
  public AviatorObject call(final Map<String, Object> env, final AviatorObject arg1,
      final AviatorObject arg2, final AviatorObject arg3, final AviatorObject arg4,
      final AviatorObject arg5, final AviatorObject arg6, final AviatorObject arg7,
      final AviatorObject arg8, final AviatorObject arg9, final AviatorObject arg10) {
    return throwArity(10);
  }


  @Override
  public AviatorObject call(final Map<String, Object> env, final AviatorObject arg1,
      final AviatorObject arg2, final AviatorObject arg3, final AviatorObject arg4,
      final AviatorObject arg5, final AviatorObject arg6, final AviatorObject arg7,
      final AviatorObject arg8, final AviatorObject arg9, final AviatorObject arg10,
      final AviatorObject arg11) {
    return throwArity(11);
  }


  @Override
  public AviatorObject call(final Map<String, Object> env, final AviatorObject arg1,
      final AviatorObject arg2, final AviatorObject arg3, final AviatorObject arg4,
      final AviatorObject arg5, final AviatorObject arg6, final AviatorObject arg7,
      final AviatorObject arg8, final AviatorObject arg9, final AviatorObject arg10,
      final AviatorObject arg11, final AviatorObject arg12) {
    return throwArity(12);
  }


  @Override
  public AviatorObject call(final Map<String, Object> env, final AviatorObject arg1,
      final AviatorObject arg2, final AviatorObject arg3, final AviatorObject arg4,
      final AviatorObject arg5, final AviatorObject arg6, final AviatorObject arg7,
      final AviatorObject arg8, final AviatorObject arg9, final AviatorObject arg10,
      final AviatorObject arg11, final AviatorObject arg12, final AviatorObject arg13) {
    return throwArity(13);
  }


  @Override
  public AviatorObject call(final Map<String, Object> env, final AviatorObject arg1,
      final AviatorObject arg2, final AviatorObject arg3, final AviatorObject arg4,
      final AviatorObject arg5, final AviatorObject arg6, final AviatorObject arg7,
      final AviatorObject arg8, final AviatorObject arg9, final AviatorObject arg10,
      final AviatorObject arg11, final AviatorObject arg12, final AviatorObject arg13,
      final AviatorObject arg14) {
    return throwArity(14);
  }


  @Override
  public AviatorObject call(final Map<String, Object> env, final AviatorObject arg1,
      final AviatorObject arg2, final AviatorObject arg3, final AviatorObject arg4,
      final AviatorObject arg5, final AviatorObject arg6, final AviatorObject arg7,
      final AviatorObject arg8, final AviatorObject arg9, final AviatorObject arg10,
      final AviatorObject arg11, final AviatorObject arg12, final AviatorObject arg13,
      final AviatorObject arg14, final AviatorObject arg15) {
    return throwArity(15);
  }


  @Override
  public AviatorObject call(final Map<String, Object> env, final AviatorObject arg1,
      final AviatorObject arg2, final AviatorObject arg3, final AviatorObject arg4,
      final AviatorObject arg5, final AviatorObject arg6, final AviatorObject arg7,
      final AviatorObject arg8, final AviatorObject arg9, final AviatorObject arg10,
      final AviatorObject arg11, final AviatorObject arg12, final AviatorObject arg13,
      final AviatorObject arg14, final AviatorObject arg15, final AviatorObject arg16) {
    return throwArity(16);
  }


  @Override
  public AviatorObject call(final Map<String, Object> env, final AviatorObject arg1,
      final AviatorObject arg2, final AviatorObject arg3, final AviatorObject arg4,
      final AviatorObject arg5, final AviatorObject arg6, final AviatorObject arg7,
      final AviatorObject arg8, final AviatorObject arg9, final AviatorObject arg10,
      final AviatorObject arg11, final AviatorObject arg12, final AviatorObject arg13,
      final AviatorObject arg14, final AviatorObject arg15, final AviatorObject arg16,
      final AviatorObject arg17) {
    return throwArity(17);
  }


  @Override
  public AviatorObject call(final Map<String, Object> env, final AviatorObject arg1,
      final AviatorObject arg2, final AviatorObject arg3, final AviatorObject arg4,
      final AviatorObject arg5, final AviatorObject arg6, final AviatorObject arg7,
      final AviatorObject arg8, final AviatorObject arg9, final AviatorObject arg10,
      final AviatorObject arg11, final AviatorObject arg12, final AviatorObject arg13,
      final AviatorObject arg14, final AviatorObject arg15, final AviatorObject arg16,
      final AviatorObject arg17, final AviatorObject arg18) {
    return throwArity(18);
  }


  @Override
  public AviatorObject call(final Map<String, Object> env, final AviatorObject arg1,
      final AviatorObject arg2, final AviatorObject arg3, final AviatorObject arg4,
      final AviatorObject arg5, final AviatorObject arg6, final AviatorObject arg7,
      final AviatorObject arg8, final AviatorObject arg9, final AviatorObject arg10,
      final AviatorObject arg11, final AviatorObject arg12, final AviatorObject arg13,
      final AviatorObject arg14, final AviatorObject arg15, final AviatorObject arg16,
      final AviatorObject arg17, final AviatorObject arg18, final AviatorObject arg19) {
    return throwArity(19);
  }


  @Override
  public AviatorObject call(final Map<String, Object> env, final AviatorObject arg1,
      final AviatorObject arg2, final AviatorObject arg3, final AviatorObject arg4,
      final AviatorObject arg5, final AviatorObject arg6, final AviatorObject arg7,
      final AviatorObject arg8, final AviatorObject arg9, final AviatorObject arg10,
      final AviatorObject arg11, final AviatorObject arg12, final AviatorObject arg13,
      final AviatorObject arg14, final AviatorObject arg15, final AviatorObject arg16,
      final AviatorObject arg17, final AviatorObject arg18, final AviatorObject arg19,
      final AviatorObject arg20) {
    return throwArity(20);
  }


  @Override
  public AviatorObject call(final Map<String, Object> env, final AviatorObject arg1,
      final AviatorObject arg2, final AviatorObject arg3, final AviatorObject arg4,
      final AviatorObject arg5, final AviatorObject arg6, final AviatorObject arg7,
      final AviatorObject arg8, final AviatorObject arg9, final AviatorObject arg10,
      final AviatorObject arg11, final AviatorObject arg12, final AviatorObject arg13,
      final AviatorObject arg14, final AviatorObject arg15, final AviatorObject arg16,
      final AviatorObject arg17, final AviatorObject arg18, final AviatorObject arg19,
      final AviatorObject arg20, final AviatorObject... args) {
    return throwArity(21);
  }

}

找了些网上的文章也是只实现了简单的固定参数的自定义函数。本来想放弃,后来看了下AbstractVariadicFunction实现了AviatorFunction 类,看了下有以下类都实现了此接口:

AbstractFunction
RuntimeFunctionDelegator
AbstractVariadicFunction
TraceFunction

于是一个一个实现类找看是否有支持可变参数的方法,于是在AbstractVariadicFunction 类中找到了 variadicCall() 方法,参数 AviatorObject... args 支持可变。

/**
   * Call with variadic arguments.The subclass must implement this method.
   *
   * @since 3.0.0
   * @param env
   * @param args
   * @return
   */
  public abstract AviatorObject variadicCall(Map<String, Object> env, AviatorObject... args);

示例代码

import com.googlecode.aviator.AviatorEvaluator;
import com.googlecode.aviator.Expression;
import com.googlecode.aviator.runtime.function.AbstractVariadicFunction;
import com.googlecode.aviator.runtime.function.FunctionUtils;
import com.googlecode.aviator.runtime.type.AviatorDouble;
import com.googlecode.aviator.runtime.type.AviatorObject;

import java.util.HashMap;
import java.util.Map;

/**
 * @description: Aviator表达式转换工具
 */
public class AviatorUtils {

    static {
        AviatorEvaluator.addFunction(new AvgFunction());
        AviatorEvaluator.addFunction(new SumFunction());
    }

    /**
     * 自定义 avg 函数
     */
    static class AvgFunction extends AbstractVariadicFunction {

        @Override
        public AviatorObject variadicCall(Map<String, Object> env,  AviatorObject... args) {
            Double sum = 0D;
            Integer count = 0;
            for(AviatorObject arg:args){
                Number number = FunctionUtils.getNumberValue(arg, env);
                sum+=number.doubleValue();
                count++;
            }
            return new AviatorDouble(sum / count);
        }

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

    }

    /**
     * 自定义 sum 函数
     */
    static class SumFunction extends AbstractVariadicFunction {

        @Override
        public AviatorObject variadicCall(Map<String, Object> env,  AviatorObject... args) {
            Double sum = 0D;
            for(AviatorObject arg:args){
                Number number = FunctionUtils.getNumberValue(arg, env);
                sum+=number.doubleValue();
            }
            return new AviatorDouble(sum);
        }

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

    }

    public static void main(String[] args) {
        String exp = "udfAvg(a+b,b,udfSum(b,c),udfAvg(d,e))+2";
        Map<String, Object> map = new HashMap<>();
        map.put("a",5);
        map.put("b",6);
        map.put("c",7);
        map.put("d",7.5);
        map.put("e",9.7);
        Expression compiledExp = AviatorEvaluator.compile(exp,true);
        Double result =  (Double)compiledExp.execute(map);
        System.out.println(result);
    }

}

官网

写完了又在网上找了找相关资料,于是在官方提供的云雀文档中找到了自定义可变参数函数的描述,当时通过关键字搜索也没搜到,,大家可以看看官方文档

官网gitee:https://gitee.com/imflyfish/aviatorscript-ideaplugin/

AviatorScript在线文档:https://www.yuque.com/boyan-avfmj/aviatorscript/guhmrc

8.3 自定义函数和调用 Java 方法 / 自定义函数 / 自定义可变参数函数:https://www.yuque.com/boyan-avfmj/aviatorscript/xbdgg2

  • 6
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值