Hive自定义UDF UDAF UDTF

Hive是一种构建在Hadoop上的数据仓库,Hive把SQL查询转换为一系列在Hadoop集群中运行的MapReduce作业,是MapReduce更高层次的抽象,不用编写具体的MapReduce方法。Hive将数据组织为表,这就使得HDFS上的数据有了结构,元数据即表的模式,都存储在名为metastore的数据库中。

      可以在hive的外壳环境中直接使用dfs访问hadoop的文件系统命令。

      Hive可以允许用户编写自己定义的函数UDF,来在查询中使用。Hive中有3种UDF:

      UDF: 操作单个数据行,产生单个数据行;

      UDAF: 操作多个数据行,产生一个数据行。

      UDTF: 操作一个数据行,产生多个数据行一个表作为输出。

      用户构建的UDF使用过程如下:

      第一步:继承UDF或者UDAF或者UDTF,实现特定的方法。

      第二步:将写好的类打包为jar。如hivefirst.jar.

      第三步:进入到Hive外壳环境中,利用add jar /home/hadoop/hivefirst.jar.注册该jar文件

      第四步:为该类起一个别名,create temporary function mylength as 'com.whut.StringLength';这里注意UDF只是为这个Hive会话临时定义的。

      第五步:在select中使用mylength();

 

 

自定义UDF

    1.继承org.apache.hadoop.hive.ql.exec.UDF

       2.实现evaluate函数,evaluate函数支持重载

 
  1. package cn.sina.stat.hive.udf;

  2. import java.util.Arrays;

  3. import org.apache.hadoop.hive.ql.exec.UDF;

  4. public final class SortFieldContent extends UDF {

  5. public String evaluate( final String str, String delimiter) {

  6. if (str == null ) {

  7. return null ;

  8. }

  9. if (delimiter == null) {

  10. delimiter = "," ;

  11. }

  12. String[] strs = str.split(delimiter);

  13. Arrays. sort(strs);

  14. String result = "" ;

  15. for (int i = 0; i < strs. length; i++) {

  16. if (result.length() > 0) {

  17. result.concat(delimiter);

  18. }

  19. result.concat(strs[i]);

  20. }

  21. return result;

  22. }

  23.  
  24. public String evaluate( final String str, String delimiter, String order) {

  25. if (str == null ) {

  26. return null ;

  27. }

  28. if (delimiter == null) {

  29. delimiter = "," ;

  30. }

  31. if (order != null && order.toUpperCase().equals( "ASC" )) {

  32. return evaluate(str, delimiter);

  33. } else {

  34. String[] strs = str.split(delimiter);

  35. Arrays. sort(strs);

  36. String result = "" ;

  37. for (int i = strs. length - 1; i >= 0; i--) {

  38. if (result.length() > 0) {

  39. result.concat(delimiter);

  40. }

  41. result.concat(strs[i]);

  42. }

  43. return result;

  44. }

  45. }

  46. }

注意事项:

   1,一个用户UDF必须继承org.apache.hadoop.hive.ql.exec.UDF;

   2,一个UDF必须要包含有evaluate()方法,但是该方法并不存在于UDF中。evaluate的参数个数以及类型都是用户自己定义的。在使用的时候,Hive会调用UDF的evaluate()方法。

 

自定义UDAF

1.函数类继承org.apache.hadoop.hive.ql.exec.UDAF

   内部类实现接口org.apache.hadoop.hive.ql.exec.UDAFEvaluator

2.Evaluator需要实现 init、iterate、terminatePartial、merge、terminate这几个函数

   具体执行过程如图:

 
  1. package cn.sina.stat.hive.udaf;

  2. import java.util.Arrays;

  3. import org.apache.hadoop.hive.ql.exec.UDAF;

  4. import org.apache.hadoop.hive.ql.exec.UDAFEvaluator;

  5.  
  6. public class ConcatClumnGroupByKeyWithOrder extends UDAF {

  7. public static class ConcatUDAFEvaluator implements UDAFEvaluator {

  8. public static class PartialResult {

  9. String result;

  10. String delimiter;

  11. String order;

  12. }

  13.  
  14. private PartialResult partial;

  15.  
  16. public void init() {

  17. partial = null;

  18. }

  19.  
  20. public boolean iterate(String value, String delimiter, String order) {

  21.  
  22. if (value == null) {

  23. return true;

  24. }

  25. if (partial == null) {

  26. partial = new PartialResult();

  27. partial.result = new String("");

  28. if (delimiter == null || delimiter.equals("")) {

  29. partial.delimiter = new String(",");

  30. } else {

  31. partial.delimiter = new String(delimiter);

  32. }

  33. if (order != null

  34. && (order.toUpperCase().equals("ASC") || order

  35. .toUpperCase().equals("DESC"))) {

  36. partial.order = new String(order);

  37. } else {

  38. partial.order = new String("ASC");

  39. }

  40.  
  41. }

  42. if (partial.result.length() > 0) {

  43. partial.result = partial.result.concat(partial.delimiter);

  44. }

  45.  
  46. partial.result = partial.result.concat(value);

  47.  
  48. return true;

  49. }

  50.  
  51. public PartialResult terminatePartial() {

  52. return partial;

  53. }

  54.  
  55. public boolean merge(PartialResult other) {

  56. if (other == null) {

  57. return true;

  58. }

  59. if (partial == null) {

  60. partial = new PartialResult();

  61. partial.result = new String(other.result);

  62. partial.delimiter = new String(other.delimiter);

  63. partial.order = new String(other.order);

  64. } else {

  65. if (partial.result.length() > 0) {

  66. partial.result = partial.result.concat(partial.delimiter);

  67. }

  68. partial.result = partial.result.concat(other.result);

  69. }

  70. return true;

  71. }

  72.  
  73. public String terminate() {

  74. String[] strs = partial.result.split(partial.delimiter);

  75. Arrays.sort(strs);

  76. String result = new String("");

  77. if (partial.order.equals("DESC")) {

  78. for (int i = strs.length - 1; i >= 0; i--) {

  79. if (result.length() > 0) {

  80. result.concat(partial.delimiter);

  81. }

  82. result.concat(strs[i]);

  83. }

  84. } else {

  85. for (int i = 0; i < strs.length; i++) {

  86. if (result.length() > 0) {

  87. result.concat(partial.delimiter);

  88. }

  89. result.concat(strs[i]);

  90. }

  91. }

  92. return new String(result);

  93. }

  94. }

  95. }

注意事项:

    1,用户的UDAF必须继承了org.apache.hadoop.hive.ql.exec.UDAF;

    2,用户的UDAF必须包含至少一个实现了org.apache.hadoop.hive.ql.exec的静态类,诸如常见的实现了 UDAFEvaluator。

    3,一个计算函数必须实现的5个方法的具体含义如下:

    init():主要是负责初始化计算函数并且重设其内部状态,一般就是重设其内部字段。一般在静态类中定义一个内部字段来存放最终的结果。

    iterate():每一次对一个新值进行聚集计算时候都会调用该方法,计算函数会根据聚集计算结果更新内部状态。当输入值合法或者正确计算了,则就返回true。

    terminatePartial():Hive需要部分聚集结果的时候会调用该方法,必须要返回一个封装了聚集计算当前状态的对象。

    merge():Hive进行合并一个部分聚集和另一个部分聚集的时候会调用该方法。

    terminate():Hive最终聚集结果的时候就会调用该方法。计算函数需要把状态作为一个值返回给用户。

    4,部分聚集结果的数据类型和最终结果的数据类型可以不同。

 

自定义UDTF

1.继承org.apache.hadoop.hive.ql.udf.generic.GenericUDTF
2.实现initialize, process, close三个方法
     a.initialize初始化验证,返回字段名和字段类型
     b.初始化完成后,调用process方法,对传入的参数进行处理,通过forword()方法把结果返回
     c.最后调用close()方法进行清理工作

 
  1. package cn.sina.stat.hive.udtf;

  2. import java.util.ArrayList;

  3. import java.util.Arrays;

  4. import org.apache.hadoop.hive.ql.udf.generic.GenericUDTF;

  5. import org.apache.hadoop.hive.ql.exec.UDFArgumentException;

  6. import org.apache.hadoop.hive.ql.exec.UDFArgumentLengthException;

  7. import org.apache.hadoop.hive.ql.metadata.HiveException;

  8. import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector;

  9. import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspectorFactory;

  10. import org.apache.hadoop.hive.serde2.objectinspector.StructObjectInspector;

  11. import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorFactory;

  12.  
  13. public class SortFieldExplodeToPair extends GenericUDTF {

  14.  
  15. @Override

  16. public void close() throws HiveException {

  17. // TODO Auto-generated method stub

  18. }

  19.  
  20. @Override

  21. public StructObjectInspector initialize(ObjectInspector[] args)

  22. throws UDFArgumentException {

  23. if (args.length != 3) {

  24. throw new UDFArgumentLengthException(

  25. "SortFieldExplodeToPair takes only three argument");

  26. }

  27. if (args[0].getCategory() != ObjectInspector.Category.PRIMITIVE) {

  28. throw new UDFArgumentException(

  29. "SortFieldExplodeToPair takes string as first parameter");

  30. }

  31. if (args[1].getCategory() != ObjectInspector.Category.PRIMITIVE) {

  32. throw new UDFArgumentException(

  33. "SortFieldExplodeToPair takes string as second parameter");

  34. }

  35. if (args[2].getCategory() != ObjectInspector.Category.PRIMITIVE) {

  36. throw new UDFArgumentException(

  37. "SortFieldExplodeToPair takes string as third parameter");

  38. }

  39. if (args[2] == null

  40. || !(args[2].toString().toUpperCase().equals("ASC") || args[2]

  41. .toString().toUpperCase().equals("DESC"))) {

  42. throw new UDFArgumentException(

  43. "SortFieldExplodeToPair third parameter must be \"ASC\" or \"DESC\"");

  44. }

  45.  
  46. ArrayList<String> fieldNames = new ArrayList<String>();

  47. ArrayList<ObjectInspector> fieldOIs = new ArrayList<ObjectInspector>();

  48. fieldNames.add("col1");

  49. fieldOIs.add(PrimitiveObjectInspectorFactory.javaStringObjectInspector);

  50.  
  51. return ObjectInspectorFactory.getStandardStructObjectInspector(

  52. fieldNames, fieldOIs);

  53. }

  54.  
  55. private final String[] forwardStr = new String[1];

  56.  
  57. @Override

  58. public void process(Object[] args) throws HiveException {

  59. String input = args[0].toString();

  60. String delimiter = args[1].toString();

  61. String order = args[2].toString();

  62. String[] strList = input.split(delimiter);

  63. Arrays.sort(strList);

  64. if (strList.length > 1) {

  65. if (order.toUpperCase().equals("DESC")) {

  66. for (int i = strList.length - 1; i > 0; i--) {

  67. forwardStr[0] = strList[i].concat(delimiter).concat(

  68. strList[i - 1]);

  69. forward(forwardStr);

  70. }

  71. } else {

  72. for (int i = 0; i < strList.length - 1; i++) {

  73. forwardStr[0] = strList[i].concat(delimiter).concat(

  74. strList[i + 1]);

  75. forward(forwardStr);

  76. }

  77. }

  78. } else {

  79. forward(strList);

  80. }

  81. }

  82.  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值