我是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的全面文档。
答案 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;
}
}