美文网首页
spark sql udf ,计算数学表式

spark sql udf ,计算数学表式

作者: 南修子 | 来源:发表于2020-06-15 18:36 被阅读0次

    前几天有个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<Character> 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<Double> 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 ,计算数学表式

          本文链接:https://www.haomeiwen.com/subject/aowjtktx.html