文档章节

支持脚本的 Hive 自定义函数

zqq90
 zqq90
发布于 2017/10/29 13:51
字数 734
阅读 318
收藏 3

        我们知道 Hive 目前允许我们通过 Java 定义 UDF (自定义函数), 但是需求是多样的, 固定的 UDF 往往都是不够用的, 而增加一个新的 UDF 的流程也是比较繁琐的, 尤其是通过 HiveServer 查询的时候还需要去重启.

于是我们尝试通过 Wit 自定义了一个可以指定动态代码的 UDF

先看一下效果吧:

SELECT
  wit('TYPE=OI_STRING \n main=()->"Hi WIT"'),
  wit('TYPE=OI_STRUCT(["id", "name"], [OI_INT, OI_STRING]) \n main=()->[9527, "Mr. Wit"]'),
  wit('TYPE=OI_LIST(PARAM_OIS[0].mapValueObjectInspector) \n main=(map)->map.~values().~toArray()', map("A",array("a","A"),"B",array("b","B"))), -- 获取 Map 的 values
  wit('TYPE=PARAM_OIS[0].name.oi \n main=(bean)->bean.name', named_struct("id", 9527, "name", "Mr. Wit")) -- 获取 Struct 的 name 字段
;

结果如下:

具体是怎么实现的呢?

  • 定义返回类型用的常量

    Hive 要求是 UDF 必须是强类型的, 因此需要定义返回值类型

// ObjectInspectorMethods
...
public static final PrimitiveObjectInspector OI_BOOLEAN = PrimitiveObjectInspectorFactory.javaBooleanObjectInspector;
public static final PrimitiveObjectInspector OI_BYTES = PrimitiveObjectInspectorFactory.javaByteArrayObjectInspector;
public static final PrimitiveObjectInspector OI_DATE = PrimitiveObjectInspectorFactory.javaDateObjectInspector;

public static MapObjectInspector OI_MAP(ObjectInspector keyOI, ObjectInspector valueOI) {
  return ObjectInspectorFactory.getStandardMapObjectInspector(keyOI, valueOI);
}
...
// 注册到引擎
JavaNativeUtil.addStaticMethods(manager, nativeFactory, ObjectInspectorMethods.class);
JavaNativeUtil.addConstFields(manager, nativeFactory, ObjectInspectorMethods.class);
...
  •  定义 code-first 的 Loader
[codeStringLoader :stringLoader]
codeFirst=true

[routeLoader]
loaders +='''
  code: codeStringLoader
'''
  • 执行模板获取返回类型和入口函数
returnType = (ObjectInspector) context.get(KEY_RETURN_TYPE);
witFunction = context.exportFunction(KEY_MAIN);
  • 转换并调用函数
for (int i = 1; i < arguments.length; i++) {
  params[i - 1] = copyToStandardObject(arguments[i].get(), paramOIs[i - 1]);
}
return witFunction.invoke(params);


接下来看一下更完整的成果:

-- 注册临时函数
CREATE TEMPORARY FUNCTION wit AS 'org.febit.wit.hive.WitUDF' USING JAR 'hdfs:///user/hue/wit-hive-0.3.0-SNAPSHOT-dist.jar';

-- Tip: TYPE 和 main 变量是免声明的, 其他变量需要声明
-- Tip: 使用 Lambda 表达式通常会比 function(..){..} 更简洁
WITH t AS(
  -- 我们用 concat 来实现多行, 方便阅读, 这里实际上会被优化成常量字符串传入 wit, 因此不用担心会报错
  SELECT inline(wit(concat(
  'TYPE=OI_LIST(OI_STRUCT(["id","name","scores"], [OI_INT,OI_STRING,OI_MAP(OI_STRING, OI_INT)])) \n',
  'var genScore=()->org.apache.commons.lang.math.RandomUtils::nextInt(70)+30 \n',
  'var genName=()->org.apache.commons.lang3.RandomStringUtils::randomAlphabetic(6) \n',
  'main=()-> {',
  '  var list = java.util.ArrayList::new() \n',
  '  for(id : 1001 .. 1004) { \n',
  -- 注意: Struct 需要数组/List, 字段按照声明时的顺序
  '    list.~add([id, genName(), { CourseX: genScore(), "Course A": genScore(), "Course B": genScore() }]) \n',
  '  } \n',
  '  return list \n',
  '} \n '
  )))
)
SELECT
  id, course, score,
  wit('TYPE=OI_STRING \n main=(s)-> s>=90 ? "A" : s>=75 ? "B" : s>=60 ? "C" : "D" ', score) AS Grade,
  wit('TYPE=OI_LIST(OI_INT) \n main=(n)->[n-1,n+1]', id) AS neighbor,
  wit('TYPE=OI_STRING \n main=()->java.util.UUID::randomUUID()', id) AS UUID, -- 需要传入一个非常量, 否则 Hive 可能会对结果进行优化,
  wit('TYPE=OI_STRING \n main=()->java.util.UUID::randomUUID()') AS BAD_UUID, -- 导致输出相同的值
  wit('TYPE=OI_STRING \n var i = 0 \n main = () -> i++', id) AS seq,  -- 延时公共变量, 但是非线程安全! 跨界点或者多线程无法保证递增
  0
FROM t
  LATERAL VIEW explode(scores) ex_scores AS course, score;

结果如下:

最后

代码已经上传到 gitee:  https://gitee.com/zqq90/wit-hive

另外, 千万要藏好这个方法, 千万不要有大胆的想法, 被坏人利用了分分钟破坏掉系统啊

 

 

© 著作权归作者所有

zqq90

zqq90

粉丝 70
博文 11
码字总数 5645
作品 1
海淀
程序员
私信 提问
加载中

评论(2)

zqq90
zqq90 博主

引用来自“紫电清霜”的评论

我有个大胆的想法

敢的话,可以试试
紫电清霜
紫电清霜
我有个大胆的想法
Hive 随谈(六)– Hive 的扩展特性

Hive 是一个很开放的系统,很多内容都支持用户定制,包括: 文件格式:Text File,Sequence File 内存中的数据格式: Java Integer/String, Hadoop IntWritable/Text 用户提供的 map/reduce...

红薯
2010/04/21
3.1K
1
玩转大数据系列之Apache Pig高级技能之函数编程(六)

原创不易,转载请务必注明,原创地址,谢谢配合! http://my.oschina.net/u/1027043/blog Pig系列的学习文档,希望对大家有用,感谢关注散仙! Apache Pig的前世今生 Apache Pig如何自定义UDF...

九劫散仙
2015/03/18
112
0
交互式数据分析工具 - Scriptis

Scriptis是一款支持在线写SQL、Pyspark、HiveQL等脚本,提交给Linkis执行的数据分析Web工具,且支持UDF、函数、资源管控和智能诊断等企业级特性。 核心特点: 脚本编辑:多语言、自动补全、语...

匿名
07/27
2.2K
2
大数据教程(12.3)Hive函数

本篇博客博主将分享Hive函数的基础知识. 1.内置运算符(https://cwiki.apache.org/confluence/display/Hive/LanguageManual+UDF) 2.内置函数(https://cwiki.apache.org/confluence/display......

em_aaron
01/31
27
0
【Hive】Hive基本操作及示例

1、数据库操作 (1)创建数据库 (2)查看数据库 (3)使用数据库 (4)查看数据库字段格式 (5)删除数据库 2、表操作 (1)创建表 (2)加载数据到表 LOCAL:从本地文件加载数据到hive表;...

gongxifacai_believe
2018/04/29
0
0

没有更多内容

加载失败,请刷新页面

加载更多

华为手机翻译功能怎么使用?这三种方法请务必收藏

华为手机翻译功能怎么使用?在我们的生活中会经常遇到翻译问题,许多外语不好的朋友该怎么办呢?华为手机已经为我们解决了这个问题,今天小编就教大家学会使用华为手机中的三种翻译技巧,需要...

翻译小天才
28分钟前
4
0
企业服务软件开发中需要注意的三个问题

在开发企业服务软件时,我们需要分为:业务需求、用户需求、产品需求,三大需求层次,三个层次互相关联,企业服务软件开发首先要服务业务,需要满足业务的需求,再关注用户体验,也就是用户需...

积木创意科技
31分钟前
4
0
C++容器底层数据结构

内置数组: int arr[10][10];memset(arr,0,10*10*sizeof(int)); //初始化int tmp[10][10];memcpy(arr, tmp, 10 * 10 * sizeof(int));//拷贝 void *memcpy(void *destin, void *source,......

SibylY
32分钟前
3
0
Dubbo-自适应拓展机制

背景 在 Dubbo 中,很多拓展都是通过 SPI 机制进行加载的,比如 Protocol、Cluster、LoadBalance 等,这些都是Dubbo的基础组件。这些基础组件的拓展不是在系统框架启动阶段被加载,而是拓展方...

rock-man
今天
7
0
Kali安装fcitx输入法(五笔)

安装fcitx > sudo apt-get install fcitx-rime fcitx-config-gtk3 重启 > sudo reboot fcitx配置 效果就是这样 配置输入法切换 系统设置...

yeahlife
今天
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部