HIVE提供了丰富的内置函数,但是对于一些复杂逻辑还是需要自定义函数来实现,对此,HIVE也提供了一些自定义的接口和类。
UDF:一进一出,一对一的关系数据
UDTF:一进多处,一对多的关系数据
UDAF:多进一出,多对一的关系数据
实现三个方法:
两个作用:
初始化参数,判断参数类型是否符合要求
设置输出列和类型
ArrayList<String> fieldNames = new ArrayList<String>();
ArrayList<ObjectInspector> fieldOIs = new ArrayList<ObjectInspector>();
fieldNames.add("col1"); // 列名为col1
fieldOIs.add(PrimitiveObjectInspectorFactory.javaStringObjectInspector); // 类型String
fieldNames.add("col2");
fieldOIs.add(PrimitiveObjectInspectorFactory.javaStringObjectInspector);
处理数据,通过forward方法将数据写出,没写出一次,代表为一行,可以传入一个数组
forward(result);
顾名思义,打扫干净,下一位
因为在之前的版本UDTF的initialize方法提供的是:
@Override
public StructObjectInspector initialize(ObjectInspector[] argOIs) throws UDFArgumentException {
return super.initialize(argOIs);
}
现在上述的方式已经不推荐了,改作了:
@Override
public StructObjectInspector initialize(StructObjectInspector argOIs) throws UDFArgumentException {
return super.initialize(argOIs);
}
将一个参数数组转变为了一个结构对象检查器,这个怎么使用的?
看一下super的实现:
public StructObjectInspector initialize(StructObjectInspector argOIs)
throws UDFArgumentException {
List<? extends StructField> inputFields = argOIs.getAllStructFieldRefs();
ObjectInspector[] udtfInputOIs = new ObjectInspector[inputFields.size()];
for (int i = 0; i < inputFields.size(); i++) {
udtfInputOIs[i] = inputFields.get(i).getFieldObjectInspector();
}
return initialize(udtfInputOIs);
}
如果需要校验参数类型,通过size方法校验长度,通过getTypeName方法校验类型
//对输入参数个数进行进行检验
if (argOIs.getAllStructFieldRefs().size()!=1) {
throw new UDFArgumentException ("args must be 1");
}
//对输入参数的类型校验
if(!"string".equals(argOIs.getAllStructFieldRefs().get(0).getFieldObjectInspector().getTypeName().toLower())){
throw new UDFArgumentException("args type must be string");
}
其实就是将参数列表封装成了StructObjectInspector对象,如果想要校验参数,那么通过上述的方式,可以看到,调用getAllStructFieldRefs方法,获取所有的输入列列表,遍历就可以取到参数列表了
inputFields.get(i).getFieldObjectInspector();
process方法就是处理逻辑的方法,每次输出一个forward,就会分割为一列
String[] result = comment.split(":");
forward(result);
按照逗号进行分割字符串,输出列
public class ExplodeArray extends GenericUDTF {
public StructObjectInspector initialize(StructObjectInspector argOIs) throws UDFArgumentException {
//定义返回值名称
List<String> filedNames = new ArrayList<String>();
//校验返回值类型
List<ObjectInspector> filedOIs= new ArrayList<ObjectInspector>();
filedNames.add("col1");
filedOIs.add(PrimitiveObjectInspectorFactory.javaStringObjectInspector);
return ObjectInspectorFactory.getStandardStructObjectInspector(filedNames,filedOIs);
}
public void process(Object[] objects) throws HiveException {
String comment= objects[0].toString();
String[] str = comment.split(",");
for(String s : str){
forward(s);
}
}
public void close() throws HiveException {
}
}
注意在UDTF函数中,会出现传入数据异常的问题,在这里我并没有校验参数,在实际生产中是需要校验参数的。