1.编写udf函数
引入pom文件
<dependencies>
<dependency><!-- 这个属于额外的jar包 自己按需引用 比如你想搞得函数 里面要连接mysql 这里肯定需要引入mysql的驱动包 我这个包是为了计算字符串的表达式的。 -->
<groupId>org.apache.commons</groupId>
<artifactId>commons-jexl3</artifactId>
<version>3.1</version>
</dependency>
<dependency> <!-- 这个只需provided即可,因为服务器有hive环境-->
<groupId>org.apache.hive</groupId>
<artifactId>hive-exec</artifactId>
<version>3.1.2</version>
<scope>provided</scope>
</dependency>
</dependencies>
先确定好你要写什么函数比如我要写一个 计算字符串表达式。
开始继承hive的udf接口,有很多小伙伴这个时候就喜欢看别人是怎么写的,这个时候就是体现个人差距的时候了,如何不看别人文档自己写呢?比如没网的条件下?
抄别人的 为啥不直接抄hive的呢? 想想hive什么udf函数最简单,lower/upper。照着抄就行。
public class StringCal extends GenericUDF 实现三个方法
initialize 初始化 校验参数的
evaluate 真正执行的方法
getDisplayString: desc function时 打印的话
import org.apache.commons.jexl3.JexlBuilder;
import org.apache.commons.jexl3.JexlEngine;
import org.apache.commons.jexl3.JexlExpression;
import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.hive.ql.exec.UDFArgumentException;
import org.apache.hadoop.hive.ql.exec.UDFArgumentLengthException;
import org.apache.hadoop.hive.ql.metadata.HiveException;
import org.apache.hadoop.hive.ql.udf.generic.GenericUDF;
import org.apache.hadoop.hive.ql.udf.generic.GenericUDFUtils;
import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.PrimitiveObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorConverter;
import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorFactory;
import org.apache.hadoop.hive.serde2.typeinfo.BaseCharTypeInfo;
import org.apache.hadoop.hive.serde2.typeinfo.TypeInfoFactory;
//有时间的这里写下,免得后面自己都不知道是干嘛的了。
@Description(name = "StringCal",
value = "_FUNC_(str) - Returns str with calculate result",
extended = "Example:\n"
+ " > SELECT _FUNC_('1+(-1+2.0-3.0+(4.0-5.0))+3.1-4.1+2*3+1.1*4') FROM src LIMIT 1;\n" + " '-7.2'")
public class StringCal extends GenericUDF {
private transient PrimitiveObjectInspector argumentOI;
private transient PrimitiveObjectInspectorConverter.StringConverter stringConverter;
private transient PrimitiveObjectInspector.PrimitiveCategory returnType = PrimitiveObjectInspector.PrimitiveCategory.STRING;
private transient GenericUDFUtils.StringHelper returnHelper;
//这里一大串校验,校验是不是普通类型啥的,校验是字符串还是啥,哪那么多事,反正照着抄就行,不写也没啥你自己定义的函数,别人也不会用。
@Override
public ObjectInspector initialize(ObjectInspector[] arguments) throws UDFArgumentException {
if (arguments.length != 1) {
throw new UDFArgumentLengthException(
"StringCal requires 1 argument, got " + arguments.length);
}
if (arguments[0].getCategory() != ObjectInspector.Category.PRIMITIVE) {
throw new UDFArgumentException(
"StringCal only takes primitive types, got " + argumentOI.getTypeName());
}
argumentOI = (PrimitiveObjectInspector) arguments[0];
stringConverter = new PrimitiveObjectInspectorConverter.StringConverter(argumentOI);
PrimitiveObjectInspector.PrimitiveCategory inputType = argumentOI.getPrimitiveCategory();
ObjectInspector outputOI = null;
BaseCharTypeInfo typeInfo;
switch (inputType) {
case CHAR:
// return type should have same length as the input.
returnType = inputType;
typeInfo = TypeInfoFactory.getCharTypeInfo(
GenericUDFUtils.StringHelper.getFixedStringSizeForType(argumentOI));
outputOI = PrimitiveObjectInspectorFactory.getPrimitiveWritableObjectInspector(
typeInfo);
break;
case VARCHAR:
// return type should have same length as the input.
returnType = inputType;
typeInfo = TypeInfoFactory.getVarcharTypeInfo(
GenericUDFUtils.StringHelper.getFixedStringSizeForType(argumentOI));
outputOI = PrimitiveObjectInspectorFactory.getPrimitiveWritableObjectInspector(
typeInfo);
break;
default:
returnType = PrimitiveObjectInspector.PrimitiveCategory.STRING;
outputOI = PrimitiveObjectInspectorFactory.writableStringObjectInspector;
break;
}
returnHelper = new GenericUDFUtils.StringHelper(returnType);
return outputOI;
}
@Override
public Object evaluate(DeferredObject[] arguments) throws HiveException {
String val = null;
if (arguments[0] != null) {
val = (String) stringConverter.convert(arguments[0].get());
}
if (val == null) {
return null;
}
//就这里是我自己写的 其他的都是抄的lowerUdf的。
// String expressionString = "1+(-1+2.0-3.0+(4.0-5.0))+3.1-4.1+2*3+1.1*4";
JexlEngine jexlEngine = new JexlBuilder().create();
JexlExpression jexlExpression = jexlEngine.createExpression(val);
Object evaluate = jexlExpression.evaluate(null);
return returnHelper.setReturnValue(evaluate.toString());
}
@Override
public String getDisplayString(String[] children) {
return null;
}
}
然后打包成一个jar,上传的hdfs
我嫌弃打的包不好听就直接改了个名字。
然后创建函数
create function default.stringCal as 'com.chenchi.s2.function.StringCal' using jar 'hdfs:///user/hive/function/stringcalculate.jar';
建议大家用这种方式,这种方式你可以随时替换jar,使得函数都是最新的。
这个是创建函数指定用哪个jar
或者
add jar hdfs:///user/hive/function/dw_ce_analysis.jar;
create function defalut.stringcal as 'com.chenchi.s2.function.StringCal';
这个是先加载jar然后根据jar创建函数。 add jar 后list jar可以看到是在/tmp目录
注意啊 这里加上数据库的名字,否则退出会话就没了。
这里我创建了两次。就是因为没加数据库的名字,反正建议各位加下。
也可以
drop function dwdmdata.stringcal
最后享受下劳动成果。有精度误差,无伤大雅。