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. John Smith
  3. John and Ann White
  4. Ted Green
  5. 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. abstract void process(Object[] record) throws HiveException;
  5. //当没有记录处理的时候该方法会被调用,用来清理代码或者产生额外的输出
  6. abstract void close() throws HiveException;

代码实现

完整代码

[java] view plain copy

  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

[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. 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处理后的输出记录对象。

[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. 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;

输出

[plain] view plain copy

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

原文链接

http://beekeeperdata.com/posts/hadoop/2015/07/26/Hive-UDTF-Tutorial.html

时间: 2024-10-06 00:07:19

Hive UDTF开发指南的相关文章

Hive UDF开发指南

编写Apache Hive用户自定义函数(UDF)有两个不同的接口,一个非常简单,另一个...就相对复杂点. 如果你的函数读和返回都是基础数据类型(Hadoop&Hive 基本writable类型,如Text,IntWritable,LongWriable,DoubleWritable等等),那么简单的API(org.apache.hadoop.hive.ql.exec.UDF)可以胜任 但是,如果你想写一个UDF用来操作内嵌数据结构,如Map,List和Set,那么你要去熟悉org.apach

【资源共享】Rockchip I2C 开发指南 V1.0

2C设备的设备应用非常广泛,常见的包含重力传感器,触摸屏驱动芯片,音频解码等 这个文档是RK3399的I2C开发文档:<Rockchip I2C 开发指南 V1.0> 内容预览: 下载地址:http://developer.t-firefly.com/thread-12495-1-1.html

七日Python之路--第十二天(Django Web 开发指南)

<Django Web 开发指南>.貌似使用Django1.0版本,基本内容差不多,细读无妨.地址:http://www.jb51.net/books/76079.html (一)第一部分 入门 (1)内置数字工厂函数 int(12.34)会创建一个新的值为12的整数对象,而float(12)则会返回12.0. (2)其他序列操作符 连接(+),复制(*),以及检查是否是成员(in, not in) '**'.join('**')   或  '***%s***%d' % (str, int)

开发指南专题八:JEECG微云快速开发平台数据字典

   开发指南专题八:JEECG微云快速开发平台数据字典的使用 1.标签中使用数据字典 数据字典为系统中可能用到的字典类型数据提供了使用的便利性和可维护性.以下拉框标签<t:dictSelect>为例进行讲解 1.1. 标签参数 属性名 类型 描述 是否必须 默认值 typeGroupCode string 字典分组编码 是 null field string 对应表单 是 null id string 唯一标识 否 null title string 显示文本 否 null defaul

C#在Linux上的开发指南(续)

续之前的一篇开发指南http://www.cnblogs.com/RainbowInTheSky/p/5496777.html 部分人在部署的时候经常出现dll兼容问题(其实可以看小蝶惊鸿的文章,蝶神早已踩过了坑http://www.cnblogs.com/xiaodiejinghong/tag/mono/) 站点部署后建议使用webbench进行压力测试 1.Microsoft.Web.Infrastructure.dll不用上传,mono已经实现(MS的dll有api依赖的问题),Mono的

《NodeJS开发指南》学习笔记

欢迎大家指导与讨论 : ) 注:此笔记是基于<NodeJS开发指南>,并不是原著. 第一章——NodeJS简介 NodeJS是一个可以让Javascript运行在服务器端的平台,它为实时Web应用(Real-time Web)开发而生.拥有实时响应,超大规模数据要求下架构的可扩展性.它采用了单线程.异步式I/O.事件驱动式的程序设计模型.统意义上,Javscript是由ECMA.DOM.BOM组成. NodeJS采用的是单线程模型,对于所有的I/O都采用异步式的请求方式,避免了频繁的上下文切换

Angularjs中文版本开发指南发布

Angularjs中文版本开发指南发布 2014-02-16 15:49 by 破狼, 29069 阅读, 9 评论, 收藏,  编辑 从本人开始在写关于Angularjs的文章开始,也算是见证了Angularjs在国内慢慢的火起来,如今的Angularjs正式如日中天.想知道为什么Angularjs会这么火,请移步angularjs移除不必要的$watch. 也是一次偶然的机会,在Angular.js中文社区群里相遇一群Angular的爱好者,在一次巧妙的交谈,大家对于Angular官方的Gu

开发指南专题十:JEECG微云快速开发平台--表单校验组件ValidForm

10.4Validform对象[方法支持链式调用] 如示例 var demo=$(".formsub").Validform(),那么demo对象会有以下属性和方法可以调用: tipmsg[object] 如:demo.tipmsg.s="error! no messageinputed."; 通过该对象可以修改除 tit 以外的其他提示文字,这样可以实现同一个页面的不同表单使用不同的提示文字. 具体可修改的提示文字 $.Tipmsg={//默认提示文字; tit:

开发指南专题五:JEECG微云快速开发平台代码生成器

开发指南专题五:JEECG微云快速开发平台代码生成器 1.1. Maven开发环境搭建 在搭建jeecg的maven开发环境之前,需要先配置好本机的maven环境,并在eclipse中安装好m2eclipse插件. 1. maven版本的工程目录,代码结构如图311所示. 2. 针对本机开发环境(这里以eclipse为例),调整依赖包和项目属性 首先在工程上右键->properties,在builders选项卡中删除掉不存在或不需要的builders,如图312所示. 然后进入Java Bu