需要apache Phoenix UDFs指南

时间:2016-08-25 17:36:15

标签: apache phoenix

我是apache phoenix的新手。我们需要写凤凰udfs。但我发现它的文档非常有限:在博客上: http://phoenix-hbase.blogspot.in/2013/04/how-to-add-your-own-built-in-function.html 上面的链接只是提供了非常简单的功能,它只有单个i / p和o / p类型。 我正在搜索一周,但找不到任何文档解释如何编写带有多个参数的评估函数,并可以根据输入返回不同的数据类型。我目前所知的只是了解内置函数的凤凰源代码。这很麻烦。有没有关于Phoenix UDF的全面文档。

2 个答案:

答案 0 :(得分:2)

我也在尝试Phoenix,需要编写UDF。以下是我迄今为止学到的一些事情。

您可以创建一个UDF,它通过以下方式获取多个输入:

1)为类定义两个参数,如此 @FunctionParseNode.BuiltInFunction( name = BitmapUnionUDF.NAME, args = { @FunctionParseNode.Argument(allowedTypes = {PBinary.class}), @FunctionParseNode.Argument(allowedTypes = {PBinary.class}) } ) public class BitmapIntersectionLengthUDF extends ScalarFunction {

2)访问评估函数内的参数
Expression arg1 = getChildren().get(0); Expression arg2 = getChildren().get(1);

3)实际从每个参数的表达式中获取字节值:

if (!arg1.evaluate(tuple, ptr)) { return false; }

- 这将ptr设置为指向arg1的值 4)检索arg1的值的字节 ptr.copyBytes()

- 这将返回一个字节数组,您可以将其转换为适当的类型。

5)注册jar和功能 CREATE FUNCTION BITMAP_INTERSECTION_LENGTH(varbinary,varbinary) returns integer as 'com.xxx.yyyy.zzz.BitmapIntersectionLengthUDF' using jar '/path/to/jar';

6)phoenix.apache.org/udf.html有关于如何/放置罐子以及设置配置的更多提示。

答案 1 :(得分:0)

package com.mohitgarg.hadoop.phoenixudf;

import java.math.BigDecimal;
import java.sql.SQLException;
import java.util.List;

import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
import org.apache.phoenix.compile.KeyPart;
import org.apache.phoenix.expression.Expression;
import org.apache.phoenix.expression.function.ScalarFunction;
import org.apache.phoenix.parse.FunctionParseNode.Argument;
import org.apache.phoenix.parse.FunctionParseNode.BuiltInFunction;
import org.apache.phoenix.schema.tuple.Tuple;
import org.apache.phoenix.schema.types.PDataType;
import org.apache.phoenix.schema.types.PDecimal;
import org.apache.phoenix.schema.types.PInteger;
import org.apache.phoenix.schema.types.PVarchar;

/**
 * 
 * @author mohit.garg
 *
 */
@BuiltInFunction(name = PaymentAmountUDF.FUNC_NAME, args = { @Argument(allowedTypes = {PVarchar.class}),
        @Argument(allowedTypes = {PInteger.class}),
        @Argument(allowedTypes = {PDecimal.class}),
        @Argument(allowedTypes = {PDecimal.class}),
        @Argument(allowedTypes = {PDecimal.class})
})
public class PaymentAmountUDF extends ScalarFunction {

    public static final String FUNC_NAME = "PaymentAmount";

    public PaymentAmountUDF() {
    }

    public PaymentAmountUDF(List<Expression> children) throws SQLException {
        super(children);
    }

    @Override
    public String getName() {
        return FUNC_NAME;
    }

    /**
     * Determines whether or not a function may be used to form the start/stop
     * key of a scan
     * 
     * @return the zero-based position of the argument to traverse into to look
     *         for a primary key column reference, or {@value #NO_TRAVERSAL} if
     *         the function cannot be used to form the scan key.
     */
    public int getKeyFormationTraversalIndex() {
        return NO_TRAVERSAL;
    }

    /**
     * Manufactures a KeyPart used to construct the KeyRange given a constant
     * and a comparison operator.
     * 
     * @param childPart
     *            the KeyPart formulated for the child expression at the
     *            {@link #getKeyFormationTraversalIndex()} position.
     * @return the KeyPart for constructing the KeyRange for this function.
     */
    public KeyPart newKeyPart(KeyPart childPart) {
        return null;
    }

    /**
     * Determines whether or not the result of the function invocation will be
     * ordered in the same way as the input to the function. Returning YES
     * enables an optimization to occur when a GROUP BY contains function
     * invocations using the leading PK column(s).
     * 
     * @return YES if the function invocation will always preserve order for the
     *         inputs versus the outputs and false otherwise, YES_IF_LAST if the
     *         function preserves order, but any further column reference would
     *         not continue to preserve order, and NO if the function does not
     *         preserve order.
     */
    public OrderPreserving preservesOrder() {
        return OrderPreserving.NO;
    }

    /**
     * is the method to be implemented which provides access to the Tuple
     * 
     * @param tuple
     *            Single row result during scan iteration
     * @param ptr
     *            Pointer to byte value being accessed
     * @return
     */
    public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) {

        String frequency = null;
        Integer term = null;
        BigDecimal interestRate = null;
        BigDecimal loanAmount = null;
        BigDecimal fee = null;

        for (int i = 0; i <= 4; i++) {

            Expression arg = getChildren().get(i);
            if (!arg.evaluate(tuple, ptr)) {
                return false;
            }
            switch (i) {
            case 0:
                frequency = new String( ptr.copyBytes());
                break;
            case 1: 
                term = (Integer) PInteger.INSTANCE.toObject(ptr);
                break;
            case 2:
                interestRate = (BigDecimal)PDecimal.INSTANCE.toObject(ptr, PDecimal.INSTANCE);
                break;
            case 3:        
                loanAmount = (BigDecimal)PDecimal.INSTANCE.toObject(ptr, PDecimal.INSTANCE);
                break;
            case 4:        
                fee = (BigDecimal)PDecimal.INSTANCE.toObject(ptr, PDecimal.INSTANCE);    
                break;
            default:
                return true;
            }
        }

        int tp = 0;
        String upcaseFrequency = frequency.toUpperCase();
        if(upcaseFrequency.equals("M")) {
            tp = 12;
        } else if(upcaseFrequency.equals("T")) {
            tp = 13;
        } else if(upcaseFrequency.equals("B")) {
            tp = 26;
        } else if(upcaseFrequency.equals("S")) {
            tp = 24;
        } else if(upcaseFrequency.equals("W")) {
            tp = 52;
        }

        int inst = (int) (Math.ceil((term / 12) * tp));
        double r = interestRate.doubleValue() / tp;
        double po = 1 - Math.pow(r + 1, -1 * inst);
        double por = r / po;
        double paymentAmount = ((por) * (loanAmount.doubleValue()  + fee.doubleValue() ));
        BigDecimal decimalPaymentAmount = BigDecimal.valueOf(paymentAmount).setScale(2, BigDecimal.ROUND_HALF_UP);
        ptr.set(PDecimal.INSTANCE.toBytes(decimalPaymentAmount));

        return true;
    }

    public PDataType getDataType() {
        return PDecimal.INSTANCE;
    }

}