Hive UDTF开发指南_oneworld_0404的博客-程序员秘密

Hive UDTF开发指南

  

在这篇文章中,我们将深入了解用户定义表函数(UDTF),该函数的实现是通过继承org.apache.Hadoop.hive.ql.udf.generic.GenericUDTF这个抽象通用类,UDTF相对UDF更为复杂,但是通过它,我们读入一个数据域,输出多行多列,而UDF只能输出单行单列。

 

代码

文章中所有的代码可以在这里找到:hive examplesGitHub repository

 

示例数据

首先先创建一张包含示例数据的表:people,该表只有name一列,该列中包含了一个或多个名字,该表数据保存在people.txt文件中。
[plain]  view plain  copy
 
  1. ~$ cat ./people.txt  
  2.   
  3. John Smith  
  4. John and Ann White  
  5. Ted Green  
  6. Dorothy  
把该文件上载到hdfs目录/user/matthew/people中:
[plain]  view plain  copy
 
  1. hadoop fs -mkdir people  
  2. hadoop fs -put ./people.txt people  

下面要创建hive外部表,在hive shell中执行
[sql]  view plain  copy
 
  1. CREATE EXTERNAL TABLE people (name string)  
  2. ROW FORMAT DELIMITED FIELDS   
  3.     TERMINATED BY '\t'   
  4.     ESCAPED BY ''   
  5.     LINES TERMINATED BY '\n'  
  6. STORED AS TEXTFILE   
  7. LOCATION '/user/matthew/people';  

UDTF的输出值

上一文章讲解的UDF与GenericUDF函数是操作单个数据域。它们必须要返回一个值。但是这并不适用于所用的数据处理任务。Hive可以存储许多类型的数据,而有时候我们并不想单数据域输入、单数据域输出。对于每一行的输入,可能我们想输出多行,又或是不输出,举个例子,想一下函数explode(一个hive内置函数)的作用。
同样,可能我们也想输出多列,而不是输出单列。
以上所有的要求我们可以用UDTF去完成。
 

实例

首先我们先假设我们想清洗people这张表中的人名,这个新的表有:
1、姓和名 两个分开的列
2、所有记录都包含姓名
3、每条记录或有包含多个人名(eg Nick and Nicole Smith)
为了达到这个实例目的,我们将实现以下API:
[java]  view plain  copy
 
  1. org.apache.hadoop.hive.ql.udf.generic.GenericUDTF  
我们将覆盖以下三个方法:
[java]  view plain  copy
 
  1. //该方法中,我们将指定输入输出参数:输入参数的ObjectInspector与输出参数的StructObjectInspector  
  2. abstract StructObjectInspector initialize(ObjectInspector[] args) throws UDFArgumentException;   
  3.   
  4. //我们将处理一条输入记录,输出若干条结果记录  
  5. abstract void process(Object[] record) throws HiveException;  
  6.   
  7. //当没有记录处理的时候该方法会被调用,用来清理代码或者产生额外的输出  
  8. abstract void close() throws HiveException;  

代码实现

 

完整代码

[java]  view plain  copy
 
  1. public class NameParserGenericUDTF extends GenericUDTF {  
  2.   
  3.       private PrimitiveObjectInspector stringOI = null;  
  4.   
  5.       @Override  
  6.       public StructObjectInspector initialize(ObjectInspector[] args) UDFArgumentException {  
  7.   
  8.         if (args.length != 1) {  
  9.           throw new UDFArgumentException("NameParserGenericUDTF() takes exactly one argument");  
  10.         }  
  11.   
  12.         if (args[0].getCategory() != ObjectInspector.Category.PRIMITIVE  
  13.             && ((PrimitiveObjectInspector) args[0]).getPrimitiveCategory() != PrimitiveObjectInspector.PrimitiveCategory.STRING) {  
  14.           throw new UDFArgumentException("NameParserGenericUDTF() takes a string as a parameter");  
  15.         }  
  16.           
  17.         // 输入格式(inspectors)  
  18.         stringOI = (PrimitiveObjectInspector) args[0];  
  19.   
  20.         // 输出格式(inspectors) -- 有两个属性的对象  
  21.         List<String> fieldNames = new ArrayList<String>(2);  
  22.         List<ObjectInspector> fieldOIs = new ArrayList<ObjectInspector>(2);  
  23.         fieldNames.add("name");  
  24.         fieldNames.add("surname");  
  25.         fieldOIs.add(PrimitiveObjectInspectorFactory.javaStringObjectInspector);  
  26.         fieldOIs.add(PrimitiveObjectInspectorFactory.javaStringObjectInspector);  
  27.         return ObjectInspectorFactory.getStandardStructObjectInspector(fieldNames, fieldOIs);  
  28.       }  
  29.             
  30.       public ArrayList<Object[]> processInputRecord(String name){  
  31.             ArrayList<Object[]> result = new ArrayList<Object[]>();  
  32.             
  33.             // 忽略null值与空值  
  34.             if (name == null || name.isEmpty()) {  
  35.               return result;  
  36.             }  
  37.               
  38.             String[] tokens = name.split("\\s+");  
  39.               
  40.             if (tokens.length == 2){  
  41.                 result.add(new Object[] { tokens[0], tokens[1] });  
  42.             }else if (tokens.length == 4 && tokens[1].equals("and")){  
  43.                 result.add(new Object[] { tokens[0], tokens[3] });  
  44.                 result.add(new Object[] { tokens[2], tokens[3] });  
  45.             }  
  46.               
  47.             return result;  
  48.       }  
  49.         
  50.       @Override  
  51.       public void process(Object[] record) throws HiveException {  
  52.   
  53.         final String name = stringOI.getPrimitiveJavaObject(record[0]).toString();  
  54.   
  55.         ArrayList<Object[]> results = processInputRecord(name);  
  56.   
  57.         Iterator<Object[]> it = results.iterator();  
  58.           
  59.         while (it.hasNext()){  
  60.             Object[] r = it.next();  
  61.             forward(r);  
  62.         }  
  63.       }  
  64.   
  65.       @Override  
  66.       public void close() throws HiveException {  
  67.         // do nothing  
  68.       }  
  69. }  
以上代码可以从:github目录 check 下来。
 

代码走读

该UDTF以string类型作为参数,返回一个拥有两个属性的对象,与GenericUDF比较相似,指定输入输出数据格式(objectinspector),以便hive能识别输入与输出。

我们为输入的string参数定义了数据格式PrimitiveObjectInspector
[java]  view plain  copy
 
  1. stringOI = (PrimitiveObjectInspector) args[0]  

定义输出数据格式(objectinspectors) 需要我们先定义两个属性名称,因为(objectinspectors)需要读取每一个属性(在这个实例中,两个属性都是string类型)。
[java]  view plain  copy
 
  1. List<String> fieldNames = new ArrayList<String>(2);  
  2. fieldNames.add("name");  
  3. fieldNames.add("surname");  
  4.   
  5. List<ObjectInspector> fieldOIs = new ArrayList<ObjectInspector>(2);  
  6. fieldOIs.add(PrimitiveObjectInspectorFactory.javaStringObjectInspector);  
  7. fieldOIs.add(PrimitiveObjectInspectorFactory.javaStringObjectInspector);  
  8.   
  9. return ObjectInspectorFactory.getStandardStructObjectInspector(fieldNames, fieldOIs);  

我们主要的处理逻辑放在这个比较直观的processInputRecord方法当中。分开逻辑处理有利我们进行更简单的单元测试,而不用涉及到繁琐的objectinspector。
最后,一旦得到结果就可以对其进行forward,把基注册为hive处理后的输出记录对象。
[java]  view plain  copy
 
  1. while (it.hasNext()){  
  2.             Object[] r = it.next();  
  3.             forward(r);  
  4.     }  
  5. }  

使用该UDTF函数

我们可以在hive中创建我们自己的函数
[plain]  view plain  copy
 
  1. mvn package  
  2. cp target/hive-extensions-1.0-SNAPSHOT-jar-with-dependencies.jar ./ext.jar  
然后在hive中使用
[sql]  view plain  copy
 
  1. ADD JAR ./ext.jar;  
  2.   
  3. CREATE TEMPORARY FUNCTION process_names as 'com.matthewrathbone.example.NameParserGenericUDTF';   
  4.   
  5. SELECT   
  6.     adTable.name,  
  7.     adTable.surname   
  8. FROM people   
  9.     lateral view process_names(name) adTable as name, surname;  
输出
[plain]  view plain  copy
 
  1. OK  
  2. John    Smith  
  3. John    White  
  4. Ann     White  
  5. Ted     Green  

原文链接

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_39946652/article/details/78790059

智能推荐

java就业前景如何?如何成为一名Java工程师?_dirft_din的博客-程序员秘密

java的就业前景还是非常可观的,在编程排行榜上java的地位一直不低,曾经在一段时间始终排在第一,今年随着很多编程语言的崛起,java的地位虽说有一定的徘徊,但是始终都在前三。薪资待遇首先我们去职友集网看下现在 java 开发工程师的薪资待遇:这个是上海java开发工程师的薪资待遇,这个薪资和广州,深圳,北京java开发工程师的薪资待遇相差不大。只要自己系统的去掌握好java,多做项目,积累经验,可以独立的完成项目框架开发,这样你的发展空间就更大。从2008年开始JAVA就突然火了起来,腾讯最近

分类(类别)_weixin_30532973的博客-程序员秘密

类别:通过分类给某一个类扩充方法,也分为声明和实现两个部分1、分类是用于给原有类添加方法,它只能添加方法,不能添加属性(成员变量)2、分类中的@property,只会生成setter/getter方法的声明,不会生成实现以及私有的成员变量3、可以在分类中访问原有类的.h的属性注意:如果分类中有和原有类同名的方法,会调用分类中的方法,也就是忽略原有类的方法在开发中尽量不要这样写...

spring源码解析---spring-core(三)_程序员ken的博客-程序员秘密

getBean 这里便是bean初始化的核心逻辑。源码比较复杂,分开说。以getBean(String name)为例。AbstractBeanFactory.getBean: @OverridepublicObjectgetBean(Stringname) throwsBeansException{ returndoGetBean(name,null,null,false); } 第二个参数表示bean的Class类型,第三个表示创建...

【异常】记一次前端因资源无法加载导致白屏异常问题_publishpath_本本本添哥的博客-程序员秘密

(1)对npm的构建不熟悉,导致了scripts脚本都会写错。(2)对webpack不熟悉,不懂构建webpack是如何控制构建结果的。

由packagename得到应用程序信息_通过应用包名获得应用信息的方法_阿狸猿的博客-程序员秘密

有的时候,项目会需要调用别人的应用程序,比如拨号、短信什么的(都是现在rom改的太多了,这些基础应用都一样,碎片化太严重),下面我给出两种方法来实现:一、通过packmanager的getLaunchIntentForPackage方法[html] view plaincopyPackageManager packageManager

Java集合类解析_weixin_30600503的博客-程序员秘密

https://www.cnblogs.com/xiohao/p/4309462.htmlJava API指的就是JDK中提供的各种功能的Java类。--集合与数组:数组(可以存储基本数据类型)是用来存放对象的一种容器,但是数组的长度固定,不适合在对象数量未知的情况下使用。集合(只能存储对象,对象类型可以不一样)的长度可变,可在多数情况下使用。--Java集合类:所有集合都是可迭代的。...

随便推点

软件测试报告怎么编写?第三方性能报告范文模板来了_锦都不二的博客-程序员秘密

目录前言一、测试报告内容怎么编写?二、第三方性能测试报告范文模板结语软件测试报告是软件测试人员针对产品执行性能测试、功能测试、系统测试等一系列操作生成的测试报告文档。一份清楚记录、分析精确的测试报告文档能帮助测试人员了解测试进度、记录产品的缺陷问题,从而更好地完善产品质量。在测试报告编写过程中,所有测试工作出发点都是围绕产品进行的,同时需要对测试人员进度测试管理都有个详细的报告分析。那么测试报告内容应该如何编写呢?小编就以第三方性能测试报告范文模板进行分析,仅供参考。一般来说测试报告内容可以从以下几个部分展

AsyncTask获取数据_开心就好吧的博客-程序员秘密

public class Fragment02 extends Fragment {    private static final String TAG = &quot;Fragment02&quot;;    private TextView name, address;    @Nullable    @Override    public View onCreateView(@NonNull LayoutIn...

TOJ 2378_Laimic_的博客-程序员秘密

题目连接:http://acm.tzc.edu.cn/acmhome/problemdetail.do?&method=showdetail&id=2378题目类型:动态规划 - 01背包数据结构:// 重量 人数 int dp[25005][105];思路分析:---------------------------------------

深度学习一、MNIST机器学习入门_深度学习mnist_东城青年的博客-程序员秘密

一、认识MNIST数据集下载数据集,tensorflow中封装了MNIST数据集:#导入(下载)MNIST数据集import tensorflow as tf#从tensorflow模块导入input_datafrom tensorflow.examples.tutorials.mnist import input_data#从MNIST_data中读取MNIST数据,这条语句在...

eclipse调试java web_eclipse调试web项目_迟趣的博客-程序员秘密

在Eclipse中开发Web项目的首要难题就是如何进行代码调试。本文简要说明一下在Eclipse中使用Tomcat和Jetty调试Java Web项目的方法。Tomcat插件方式。Eclipse自身可以通过下载安装Tomcat插件的方式进行调试,由于插件中集成了tomcat的运行环境,所以不需要独立安装Tomcat服务器。该插件网址http://www.eclipsetotale.com/tomc...

Oracle的表级锁_oracle 表级锁_q3dxdx的博客-程序员秘密

Lock mode in which the session holds the lock,Oracle的表级锁有如下级别(行级锁就他妈一个:行级排他锁): 0级 - none 1级 - null (NULL) 2级 - row-S (SS/RS),行共享 锁定语句:lock table test in row share mod

推荐文章

热门文章

相关标签