hive udf&udaf开发
来源:互联网 发布:张孝祥java百度网盘 编辑:程序博客网 时间:2024/05/22 12:09
前言
由于之前对hadoop,hive源码了解不多,因此在进行udf和udaf开发时,遇到诸多问题,还是要有时间多看看源码。
UDF
进行UDF开发主要分为两种情况,根据UDF输入参数的类型进行区分。
调用UDF时传参是基本数据类型
若是hive调用UDF时传入的是基本数据类型如string,integer可以通过直接继承org.apache.hadoop.hive.ql.exec.UDF来进行开发。并且hadoop和java的数据类型之间不用进行转换处理(这在我们进行通用udf开发的时候要注意)。主要步骤:
1)继承org.apache.hadoop.hive.ql.exec.UDF
2)实现evaluate方法,此方法可进行重载
如下例子:
import org.apache.hadoop.hive.ql.exec.UDF;public class Add extends UDF {public Integer evaluate(Integer a, Integer b) { if (null == a || null == b) { return null; } return a + b;}public Double evaluate(Double a, Double b) { if (a == null || b == null) return null; return a + b; }}
调用UDF时传参是复杂类型
若是hive调用UDF时传入的是是复杂类型,如map,list等内嵌数据结构时,使用简单udf的开发方式是不行的,我们可以通过实现org.apache.hadoop.hive.ql.udf.generic.GenericUDF来写出通用的udf。
主要步骤:
1)实现org.apache.hadoop.hive.ql.udf.generic.GenericUDF
2) 重写initialize方法,此方法主要用来检测输入参数,并得到输入参数的Inspector,用来在evaluate方法解析参数(暂时这么理解)
3)重写evaluate方法,这是开发udf的主要逻辑部分
4)重写getDisplayString方法,此方法主要用来描述此udf。出错时会显示
以下是之前实现过对输入map类型进行处理的udf
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.serde2.objectinspector.MapObjectInspector;import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector;import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspectorFactory;import org.apache.hadoop.hive.serde2.objectinspector.primitive.IntObjectInspector;import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorFactory;import org.apache.hadoop.io.Text;import java.util.HashMap;import java.util.Iterator;import java.util.Map;public class UDFmapValueScale extends GenericUDF{ private MapObjectInspector map; private IntObjectInspector flag; @Override public ObjectInspector initialize(ObjectInspector[] objectInspectors) throws UDFArgumentException { if(objectInspectors.length!=2){ throw new UDFArgumentLengthException("this only support 2 args"); } ObjectInspector a=objectInspectors[0]; ObjectInspector b=objectInspectors[1];// System.out.println(a.toString()+b.toString()); if(!(a instanceof MapObjectInspector) ||!(b instanceof IntObjectInspector)){ throw new UDFArgumentException("the argument must be a map"); } this.map=(MapObjectInspector)a; this.flag=(IntObjectInspector)b; ObjectInspector returnType= ObjectInspectorFactory.getStandardMapObjectInspector( PrimitiveObjectInspectorFactory.javaStringObjectInspector, PrimitiveObjectInspectorFactory.javaStringObjectInspector ); return returnType; } @Override public Object evaluate(DeferredObject[] deferredObjects) throws HiveException { Map<Text, Text> getMap = (Map<Text, Text>) this.map.getMap(deferredObjects[0].get()); if(getMap==null){ return null; } Integer i=(Integer) this.flag.getPrimitiveJavaObject(deferredObjects[1].get()); Map<String, String> retMap=new HashMap<>(); Iterator iter; iter = getMap.entrySet().iterator(); while(iter.hasNext()){ Map.Entry entry = (Map.Entry) iter.next(); String key=entry.getKey().toString(); Double value=Double.parseDouble(entry.getValue().toString()); if(i!=0) { value = (value + 1) * 100 / 2; } Double t=Math.rint(value); retMap.put(key,t.toString()); } return retMap; } @Override public String getDisplayString(String[] strings) { return "return a map" ; }}
初次开发的时候,遇到过很多问题,记录两点
1)对于输入空值的处理,在hive中null是普遍存在的。起初我认为null值得判断应该在initialize中判断,但是null值没有类型。initialize中对输入参数的类型进行了判断,但是null值存在于任何数据类型中,在initialize中传入的是objectInspectors,并不是你要传入的值,因此不能通过判断是否为null进行实现。最后发现null处理需要在evaluate中 if(getMap==null){
return null;
}
2)数据类型,起初此处Map<Text, Text> getMap = (Map<Text, Text>) this.map.getMap(deferredObjects[0].get());
我使用的是Map<String, String> getMap = (Map<String, String>) this.map.getMap(deferredObjects[0].get());
,然后运行的时候报类型转换异常。也就是说我们在通过Inspectors.getmap()等方法获取输入参数时,返回的是hadoop的数据结构,我们在java中进行处理时,要通过tostring()或者get方法转为java数据类型。但是对于基本数据类型,我们直接可以通过getPrimitiveJavaObject方法返回java数据类型。
UDAF
UDAF主要是配合group by使用,到分组内数据进行聚合。UDAF的开发同UDF一样,根据输入参数类型不同进行区分。
传参基本数据类型
对于传参是基本类型的udaf开发我们可以简单的通过org.apache.hadoop.hive.ql.exec.UDAFEvaluator和org.apache.hadoop.hive.ql.exec.UDAF来进行实现。主要步骤:
1)继承org.apache.hadoop.hive.ql.exec.UDAF类
2)是在继承的UDAF类中实现org.apache.hadoop.hive.ql.exec.UDAFEvaluator接口
3)重写init方法,udaf的运行可分为map阶段可reduce阶段,init方法用于每个map的初始化,貌似在reduce时也会运行(暂且这么认为)
4)实现iterate方法,此方法用于输入数据的迭代,相当于map过程
5)实现terminatePartial方法,用于对iterate得到的数据进行处理,相当于combiner,Hive需要部分结果的时候会调用该方法,必须要返回一个封装了聚集计算当前状态的对象。
6)实现merge方法,用于结果聚合,接受的参数是terminatePartial的返回值
以下udaf实现了对一个字段每个值得出现次数进行计算,返回值为map,虽然通过普通hive函数也能实现,这里以此对udaf进行练习。
import org.apache.hadoop.hive.ql.exec.UDAFEvaluator;import org.apache.hadoop.hive.ql.exec.UDAF;import java.util.HashMap;import java.util.Iterator;import java.util.Map;public class UDAFMap extends UDAF{ public static class UDAFMapEvaluator implements UDAFEvaluator { private Map<String,Integer> map; public UDAFMapEvaluator(){ super(); init(); } @Override public void init() { map=new HashMap<String, Integer>(); } public boolean iterate(String s){ if(s ==null) return true; if(map.containsKey(s)){ map.put(s,map.get(s)+1); }else{ map.put(s,1); } return true; } public Map<String,Integer> terminatePartial(){ if(map.isEmpty()){ return null; }else{ return map; } } public boolean merge(Map<String,Integer> m){ if(m!=null){ Iterator iter=m.entrySet().iterator(); while (iter.hasNext()){ Map.Entry mapEntry=(Map.Entry)iter.next(); String key=(String)mapEntry.getKey(); Integer value=(Integer)mapEntry.getValue(); if(map.containsKey(key)){ map.put(key,map.get(key)+value); }else{ map.put(key,value); } } } return true; } public Map<String,Integer> terminate(){ return map; } }}
通用udaf
简单udaf,只能进行简单udaf的开发,传参只能是基本数据类型,并且貌似将要被启用,因此有必要学习一下通用udaf的开发。以下udaf的开发主要参考此文,写的比较详细,下面直接给上使用通用udaf实现以上简单udaf功能的代码。
import org.apache.hadoop.hive.ql.metadata.HiveException;import org.apache.hadoop.hive.ql.parse.SemanticException;import org.apache.hadoop.hive.ql.udf.generic.GenericUDAFEvaluator;import org.apache.hadoop.hive.ql.udf.generic.AbstractGenericUDAFResolver;import org.apache.hadoop.hive.serde2.objectinspector.MapObjectInspector;import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector;import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspectorFactory;import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorFactory;import org.apache.hadoop.hive.serde2.objectinspector.primitive.StringObjectInspector;import org.apache.hadoop.hive.serde2.typeinfo.TypeInfo;import org.apache.hadoop.io.IntWritable;import org.apache.hadoop.io.Text;import java.util.HashMap;import java.util.Map;public class GenericUDAFMap extends AbstractGenericUDAFResolver{ public GenericUDAFEvaluator getEvaluator(TypeInfo[] parameters) throws SemanticException{ return new GenericUDAFMapEvaluator(); } public static class GenericUDAFMapEvaluator extends GenericUDAFEvaluator{ private StringObjectInspector inputOI; private MapObjectInspector inputOI2; public ObjectInspector init(Mode m,ObjectInspector[] parameters) throws HiveException{ assert (parameters.length==1); super.init(m,parameters); if(m==Mode.PARTIAL1||m==Mode.COMPLETE){ inputOI=(StringObjectInspector)parameters[0]; }else{ inputOI2=(MapObjectInspector)parameters[0]; } return ObjectInspectorFactory.getStandardMapObjectInspector(PrimitiveObjectInspectorFactory.javaStringObjectInspector, PrimitiveObjectInspectorFactory.javaIntObjectInspector); } class MapBuffer implements AggregationBuffer{ Map<String,Integer> map; } @Override public AggregationBuffer getNewAggregationBuffer() throws HiveException { MapBuffer mb=new MapBuffer(); reset(mb); return mb; } @Override public void reset(AggregationBuffer aggregationBuffer) throws HiveException { ((MapBuffer)aggregationBuffer).map=new HashMap<>(); } @Override public void iterate(AggregationBuffer aggregationBuffer, Object[] objects) throws HiveException { //普通类型可以直接通过getPrimitiveJavaObject得到java类型 String s=this.inputOI.getPrimitiveJavaObject(objects[0]); if(s!=null){ MapBuffer mb=(MapBuffer)aggregationBuffer; if(mb.map.containsKey(s)){ mb.map.put(s,mb.map.get(s)+1); }else{ mb.map.put(s,1); } } } @Override public Object terminatePartial(AggregationBuffer aggregationBuffer) throws HiveException { return ((MapBuffer)aggregationBuffer).map; } @Override public void merge(AggregationBuffer aggregationBuffer, Object o) throws HiveException { MapBuffer mb=(MapBuffer)aggregationBuffer; //虽然上面定以了Map<String,Integer>,但是作为map的中间结果,猜测hadoop可能将其进行了序列化,变成了Text与IntWriteable Map<Text,IntWritable> map=(Map<Text,IntWritable>)inputOI2.getMap(o); for(Map.Entry<Text,IntWritable> entry: map.entrySet()){ String key=entry.getKey().toString(); Integer value=entry.getValue().get(); if(mb.map.containsKey(key)){ mb.map.put(key,mb.map.get(key)+value); }else{ mb.map.put(key,value); } } } @Override public Object terminate(AggregationBuffer aggregationBuffer) throws HiveException { return ((MapBuffer)aggregationBuffer).map; } }}
问题记录:同样是数据类型转换问题,我们在进行通用udaf开发是一定要注意。
参考文献
http://blog.csdn.net/kent7306/article/details/50110067
- hive udf&udaf开发
- Hive UDF与UDAF
- HIVE UDF/UDAF/UDTF
- hive UDF UDAF
- hive udf 与udaf
- hive udf \udaf\udtf
- hive udf和udaf
- Hive Udf 与Udaf
- hive UDF UDAF
- hive UDF UDAF
- hive udf & udaf
- hive 自定义UDF UDAF UDTF
- hive udf和UDAF应用
- hive 的UDF和UDAF
- hive 自定义函数UDF,UDAF
- hive udf udaf 一例
- hive udf,udaf,udtf详解
- Hive自定义函数(UDF、UDAF)
- SOJ-1021-Couples算法配合数据结构的美
- 底部导航栏
- 有return的情况下try catch finally的执行顺序
- 词向量源码解析:(5.12)ngram2vec源码解析小结
- oracle创建用户并赋权
- hive udf&udaf开发
- Spark map-side-join 关联优化
- IplImage与Qimage之间转换
- JDBC知识(一)
- C++复习Pointers
- Datalab-handout数据表示实验
- 关于网站改版注意的网站优化问题
- codeforces 582A GCD Table
- [Linux] Linux之TCPIP内核参数优化