spark sql udf ,计算数学表式

前几天有个spark 任务特别的慢,原因是我写了一个udf,把一个对象作为构造函数的对象穿进去了
这个udf的功能是为了实现,把传入的数学表达式(如:20*x/(20-x)),和传入的列的值做计算,把传入的列的值替换成x

刚开始的想法就是直接用java提供的方法,就是开篇所说的,结果几十万的数据跑半小时,后面就放弃了

最终做法就是,直接在udf写计算方法,也是网上参考了一位同行的
我计算的都是double

 

    @Override
    public  Double call(Double thisv, String expstr) throws Exception {
        Double result=null;
        expstr = expstr.replace("x", String.valueOf(thisv));

        try {
            result = calculate(transfer(expstr));

        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    private static String transfer(String mathStr) {
        // 标记输出结果
        StringBuilder result = new StringBuilder();
        StringBuilder ysfresult = new StringBuilder();
        // 1.初始化一个运算符栈。
        Stack stack = new Stack();
        if (mathStr == null || mathStr.length() == 0) {
            return null;
        }
        System.out.println("--------------");
        System.out.println("中缀表达式:" + mathStr);
        boolean belong_isnum = true;//前一个是否是数字
        char[] arr = mathStr.toCharArray();
        for (int i = 0; i < arr.length; i++) {
            // 2.从算数表达式输入的字符串中依次从左向右每次读取一个字符。
            char s = arr[i];
            // 3.如果当前字符是操作数,则直接填写到后缀表达式。
            if (!Character.isDigit(s) && s != '.') {
                belong_isnum = false;
            }
            if (Character.isDigit(s) || s == '.') {

                if (belong_isnum) {
                    result.append(s);
                } else {
                    result.append("|" + s);
                }
                belong_isnum = true;
            }

            // 4.如果当前字符是(左括号,将其压入运算符栈(第一步定义)。
            else if ('(' == s) {

                stack.push(s);
            }
            // 5.如果当前字符为运算符,则
            else if ('+' == s || '-' == s || '*' == s || '/' == s) {
                if (!stack.isEmpty()) {
                    char stackTop = stack.pop();
                    // 当此运算符的优先级高于栈顶元素的时候,则将此运算符压入运算符栈
                    if (compare(s, stackTop)) {
                        stack.push(stackTop);
                        stack.push(s);
                    }
                    // 否则,弹出栈顶运算符到后缀表达式,并且将当前运算符压栈。回到步骤2.
                    else {
                        result.append("|"+stackTop);
                        stack.push(s);
                    }
                }
                // 5.1.当运算符栈为空,则将其压入运算符栈。
                else {
                    stack.push(s);
                }
            }
            // 6.如果当前字符是)右括号,反复将栈顶元素弹出到后缀表达式,直到栈顶元素是左括号(为止,并将左括号从栈中弹出丢弃。
            else if (s == ')') {
                while (!stack.isEmpty()) {
                    char item = stack.pop();
                    if (item != '(') {
                        result.append(item);
                    } else {
                        break;
                    }
                }
            }
        }
        result.insert(result.length() - 1, "|");
        while (!stack.isEmpty()) {
            ysfresult.append("|" + stack.pop());
        }
        result.append(ysfresult);
        System.out.println("后缀表达式:" + result.toString());
        return result.toString();
    }

    //比较优先级
    private static boolean compare(char s, char item) {
        if (item == '(') {
            return true;
        }
        if (s == '*' || s == '/') {
            if (item == '+' || item == '-') {
                return true;
            }
        }
        return false;
    }

    private static Double calculate(String transferToPostfix) {
        Stack stack = new Stack();
        // char[] c = transferToPostfix.toCharArray();
        String[] c = transferToPostfix.split("\\|");
        Double a, b;
        for (int i = 0; i < c.length; i++) {
            switch (c[i]) {
                case "+":
                    a = Double.parseDouble(stack.pop().toString());
                    b = Double.parseDouble(stack.pop().toString());
                    stack.push(b + a);
                    break;
                case "-":
                    a = Double.parseDouble(stack.pop().toString());
                    b = Double.parseDouble(stack.pop().toString());
                    stack.push(b - a);
                    break;
                case "*":
                    a = Double.parseDouble(stack.pop().toString());
                    b = Double.parseDouble(stack.pop().toString());
                    stack.push(b * a);
                    break;
                case "/":
                    a = Double.parseDouble(stack.pop().toString());
                    b = Double.parseDouble(stack.pop().toString());
                    stack.push(b / a);
                    break;

                default:
                    String d = c[i];
                    try {
                        stack.push(Double.parseDouble(d));
                    } catch (NumberFormatException e) {//33333.0*

                    }
                    break;
            }
        }
        return stack.pop();
    }
}
文出自,南修子,转载请注明

你可能感兴趣的:(spark sql udf ,计算数学表式)