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

代码

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

示例数据

首先先创建一张包含示例数据的表:people,该表只有name一列,该列中包含了一个或多个名字,该表数据保存在people.txt文件中。
  1. ~$ cat ./people.txt
  2. John Smith
  3. John and Ann White
  4. Ted Green
  5. Dorothy

把该文件上载到hdfs目录/user/matthew/people中:

  1. hadoop fs -mkdir people
  2. hadoop fs -put ./people.txt people

下面要创建hive外部表,在hive shell中执行

  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:
  1. org.apache.hadoop.hive.ql.udf.generic.GenericUDTF

我们将覆盖以下三个方法:

  1. //该方法中,我们将指定输入输出参数:输入参数的ObjectInspector与输出参数的StructObjectInspector
  2. abstract StructObjectInspector initialize(ObjectInspector[] args) throws UDFArgumentException;
  3. //我们将处理一条输入记录,输出若干条结果记录
  4. abstract void process(Object[] record) throws HiveException;
  5. //当没有记录处理的时候该方法会被调用,用来清理代码或者产生额外的输出
  6. abstract void close() throws HiveException;

代码实现

 

完整代码

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

以上代码可以从:github目录 check 下来。

 

代码走读

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

我们为输入的string参数定义了数据格式PrimitiveObjectInspector

  1. stringOI = (PrimitiveObjectInspector) args[0]

定义输出数据格式(objectinspectors) 需要我们先定义两个属性名称,因为(objectinspectors)需要读取每一个属性(在这个实例中,两个属性都是string类型)。

  1. List<String> fieldNames = new ArrayList<String>(2);
  2. fieldNames.add("name");
  3. fieldNames.add("surname");
  4. List<ObjectInspector> fieldOIs = new ArrayList<ObjectInspector>(2);
  5. fieldOIs.add(PrimitiveObjectInspectorFactory.javaStringObjectInspector);
  6. fieldOIs.add(PrimitiveObjectInspectorFactory.javaStringObjectInspector);
  7. return ObjectInspectorFactory.getStandardStructObjectInspector(fieldNames, fieldOIs);

我们主要的处理逻辑放在这个比较直观的processInputRecord方法当中。分开逻辑处理有利我们进行更简单的单元测试,而不用涉及到繁琐的objectinspector。

最后,一旦得到结果就可以对其进行forward,把基注册为hive处理后的输出记录对象。
  1. while (it.hasNext()){
  2. Object[] r = it.next();
  3. forward(r);
  4. }
  5. }

使用该UDTF函数

我们可以在hive中创建我们自己的函数

  1. mvn package
  2. cp target/hive-extensions-1.0-SNAPSHOT-jar-with-dependencies.jar ./ext.jar

然后在hive中使用

  1. ADD JAR ./ext.jar;
  2. CREATE TEMPORARY FUNCTION process_names as 'com.matthewrathbone.example.NameParserGenericUDTF';
  3. SELECT
  4. adTable.name,
  5. adTable.surname
  6. FROM people
  7. lateral view process_names(name) adTable as name, surname;

输出

  1. OK
  2. John    Smith
  3. John    White
  4. Ann     White
  5. Ted     Green

原文链接

Hive UDTF开发指南的更多相关文章

  1. 最强最全面的Hive SQL开发指南,超四万字全面解析

    本文整体分为两部分,第一部分是简写,如果能看懂会用,就直接从此部分查,方便快捷,如果不是很理解此SQL的用法,则查看第二部分,是详细说明,当然第二部分语句也会更全一些! 第一部分: hive模糊搜索表 ...

  2. Hive UDF开发指南

    编写Apache Hive用户自定义函数(UDF)有两个不同的接口,一个非常简单,另一个...就相对复杂点. 如果你的函数读和返回都是基础数据类型(Hadoop&Hive 基本writable ...

  3. ASP.NET Aries 开源开发框架:开发指南(一)

    前言: 上周开源了Aries开发框架后,好多朋友都Download了源码,在运行过程里,有一些共性的问题会问到. 所以本篇打算写一下简单的开发指南,照顾一下不是太看的懂源码的同学,同时也会讲解一下框架 ...

  4. FreeMarker模板开发指南知识点梳理

    freemarker是什么? 有什么用? 怎么用? (问得好,这些都是我想知道的问题) freemarker是什么? FreeMarker 是一款 模板引擎: 即一种基于模板和要改变的数据, 并用来生 ...

  5. Jetty使用教程(四:21-22)—Jetty开发指南

    二十一.嵌入式开发 21.1 Jetty嵌入式开发HelloWorld 本章节将提供一些教程,通过Jetty API快速开发嵌入式代码 21.1.1 下载Jetty的jar包 Jetty目前已经把所有 ...

  6. JVM 平台上的各种语言的开发指南

    JVM 平台上的各种语言的开发指南 为什么我们需要如此多的JVM语言? 在2013年你可以有50中JVM语言的选择来用于你的下一个项目.尽管你可以说出一大打的名字,你会准备为你的下一个项目选择一种新的 ...

  7. iOS原生地图开发指南续——大头针与自定义标注

    iOS原生地图开发指南续——大头针与自定义标注 出自:http://www.sxt.cn/info-6042-u-7372.html 在上一篇博客中http://my.oschina.net/u/23 ...

  8. Angularjs中文版本开发指南发布

    从本人开始在写关于Angularjs的文章开始,也算是见证了Angularjs在国内慢慢的火起来,如今的Angularjs正式如日中天.想知道为什么Angularjs会这么火,请移步angularjs ...

  9. nodejs开发指南读后感

    nodejs开发指南读后感 阅读目录 使用nodejs创建http服务器; supervisor的使用及nodejs常见的调式代码命令了解; 了解Node核心模块; ejs模板引擎 Express 理 ...

随机推荐

  1. ssm(Spring、Springmvc、Mybatis)实战之淘淘商城-第十四天(非原创)

    文章大纲 一.淘淘商城总体架构介绍二.淘淘商城重要技术点总结三.项目常见面试题四.项目学习(all)资源下载五.参考文章 一.淘淘商城总体架构介绍 1. 功能架构   2. 技术选型 (1)Sprin ...

  2. 常见SQL优化方法

    SQL优化的一些方法 1.对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引. 2.应尽量避免在 where 子句中对字段进行 null 值判断,否 ...

  3. js重载的实现

    在JavaScript高级程序设计书中看到 ECMAScript函数中不能想传统意义上那样实现重载.而在其他语句中(Java)中,可以为一个函数编写两个定义,只要两个定义的签名(接受的参 数的类型和数 ...

  4. H5如何做手机app(移动Web App)?图片轮播?ionic、MUI

    移动Web App 跨平台开发 用户不需要去卖场来下载安装App 任何时候都可以发布App只需要一个开发项目 可以使用HTML5,CSS3以及JavaScript以及服务器端语言来完成(PHP,Rub ...

  5. 菜鸟 学注册机编写之 “RSA”

    测试环境  系统: xp sp3 调试器 :od 1.10 RSA简单介绍 选取两个别人不知道的大素数p, q. 公共模n = p*q 欧拉值φ(n) = (p-1)(q-1) 选取公匙(加密匙) e ...

  6. Android studio 配置忽略

    直接在Ignored Files选项里点击+号,在弹出的对话框选择第二项,然后依次输入上面包含的 .gradle .idea build 三个文件夹目录,再选择第一项,找到local.properti ...

  7. python3基础11(正则表达式及re模块)

    #生成re对象 compile# 之后再期调用 match search 返回匹配到的字符串# findall 返回匹配结果的列表#如果要对匹配的结果进行分组,可加(),并可通过\数字 去应用

  8. 百倍性能的PL/SQL优化案例(r11笔记第13天)

    我相信你是被百倍性能的字样吸引了,不过我所想侧重的是优化的思路,这个比优化技巧更重要,而结果嘛,其实我不希望说成是百倍提升,“”自黑“”一下. 有一个真实想法和大家讨论一下,就是一个SQL语句如果原本 ...

  9. vuejs挂载点,模板与实例的关系

    <body> <div id='root'> <h1>{{msg}}</h1> </div> <script> new Vue( ...

  10. tableviewcell折叠问题,(类似qq列表展开形式) 多个cell同时展开,OC版 和 Swift

    之前没有用到过这块,但是今天看到,就试了试,但是发现,网上的有的方法不能多个cell同时展开,只能一个一个的展开. 我就尝试用用数组记录展开的标记的方法,功能实现了, 直接上代码: // // Vie ...