Hive反射函数的使用-程序员是怎么学UDF函数的

简介: Hive反射函数的使用-程序员是怎么学UDF函数的

前言

学习udf的时候,程序员给人感觉是知道会快些,这个答案是肯定的,因为常规的视角都是udf驱动效率,但是程序员的世界是反过来的–程序员驱动udf的效率。

udf的几座大山

学习udf函数几乎需要回答下面几个问题:

  1. 我要做这个操作有什么函数
  2. 这个函数怎么使用
  3. 我咋自己去写一个函数
  4. hive里面还有哪些骚操作

源码引入

写程序肯定是需要源码的,hive是开源的,源码可以随时查阅,很多人因为编译不过就放弃,其实源码只要可以导入idea搜索就可以了,当然能调试更好,有了源码,我们就可以各种搜索,这个就是我们学习宝库!

函数的入口

udf其实就是一堆堆的类执行函数,一般常规这种灵活的扩展性,hive是提供了注册进制来做的,我们需要找到我们的注册类:

package org.apache.hadoop.hive.ql.exec;
 ......若干引入包
/**
 * FunctionRegistry.
 */
public final class FunctionRegistry {

  private static final Logger LOG = LoggerFactory.getLogger(FunctionRegistry.class);
  ......若干代码

我们可以看到源码部分都是很有规律的函数引入,第一个参数便是函数名,第二个参数便是实现类了,不光如此,udf注册的时候在代码上面做了一个很好的分类,比如字符操作相关的会放在一起:

system.registerGenericUDF("concat", GenericUDFConcat.class);
   system.registerUDF("substr", UDFSubstr.class, false);
   ...... 

时间处理相关的,也会放在一起

system.registerUDF("day", UDFDayOfMonth.class, false);
  system.registerUDF("dayofmonth", UDFDayOfMonth.class, false);
  ...... 

我们按照有规律的排布,可以很方便找到我们要的函数。

函数的实现类

在函数头部有一段描述,比较有耐心的程序员会把这段写得很详细,这段在函数注册时候我们可以通过desc 命令看得到。

hive> desc function concat;
Begin to execute:
desc function concat;
OK
concat(str1, str2, ... strN) - returns the concatenation of str1, str2, ... strN or concat(bin1, bin2, ... binN) - returns the concatenation of bytes in binary data  bin1, bin2, ... binN
Time taken: 0.029 seconds, Fetched: 1 row(s)

测试代码

hive这种代码都是会经过大量的测试,测试代码中我们有个很关键的东西就是里面会直接写这个函数的用法,因为测试的是sql,源码中放在了.g的文件中,我们找到(通过搜索去找):

关于udf的第一手使用基本来自这个地方,在这里会覆盖各种场景和用法,基本在这个地方摸索就可以了。

反射函数

反射操作其实是程序员喜欢,但是市面上听说很少的操作,我们直接从源码找到这几个函数:

system.registerGenericUDF("reflect", GenericUDFReflect.class);
system.registerGenericUDF("reflect2",GenericUDFReflect2.class;
system.registerGenericUDF("java_method",GenericUDFReflect.clas;

我们在测试代码中找到对应的使用方法:

reflect使用

我们捡关键的部分:

SELECT reflect("java.lang.String", "valueOf", 1),
       reflect("java.lang.String", "isEmpty"),
       reflect("java.lang.Math", "max", 2, 3),
       reflect("java.lang.Math", "min", 2, 3),
       reflect("java.lang.Math", "round", 2.5D),
       round(reflect("java.lang.Math", "exp", 1.0D), 6),
       reflect("java.lang.Math", "floor", 1.9D),
       reflect("java.lang.Integer", "valueOf", key, 16)
FROM src tablesample (1 rows)

这种操作基本就秒懂,所以这个udf瞬间学会了不是么,当然,我们还是稍加解释。

reflect其实就是通过反射的形式去调用我们java中的代码,hive是java写的,调用java代码也完全不是事,这样子操作其实意味着,我们在程序中写的函数可以通过这种方式引用,一般情况下我们jdk在lang下的包我们不会主动去引用,实际上来说我们主动写上引用也是ok的:

效果一样的代码:

System.out.println(String.valueOf("2"));
   System.out.println(Math.max(2, 3));
System.out.println(java.lang.String.valueOf("2"));
 System.out.println(java.lang.Math.max(2,3));

到了udf上面反射是要加全路径的:

比如一段求最大值的操作

select reflect("java.lang.Math", "max", 2, 3);
3

reflect2

这个函数做啥的,因为我们其实已经有了reflect函数,我们还是找的测试的代码:

SELECT key,
       reflect2(key,   "byteValue"),
       reflect2(key,   "shortValue"),
       .....
       reflect2(value, "concat", "_concat"),
       reflect2(value, "contains", "86"),
       reflect2(value, "startsWith", "v"),
       reflect2(value, "endsWith", "6"),
       reflect2(value, "equals", "val_86"),
       reflect2(value, "equalsIgnoreCase", "VAL_86")
       ts,
       reflect2(ts, "getYear"),
       reflect2(ts, "getMonth"),
       reflect2(ts, "getDay"),
       .....
FROM (select cast(key as int) key, value, cast('2013-02-15 19:41:20' as timestamp) ts from src) a LIMIT 5;

事实上,就算看了这个测试代码其实也不大清楚做啥的,我们找到源码上面去看看,源码在对应类:

org.apache.hadoop.hive.ql.udf.generic.GenericUDFReflect2中,从138行开始我们找到关键逻辑:

......
 switch (returnOI.getPrimitiveCategory()) {
      case VOID:
        return null;
      case BOOLEAN:
        ((BooleanWritable)returnObj).set((Boolean)result);
        return returnObj;
      case BYTE:
        ((ByteWritable)returnObj).set((Byte)result);
        return returnObj;
      case SHORT:
        ((ShortWritable)returnObj).set((Short)result);
        return returnObj;
      case INT:
        ((IntWritable)returnObj).set((Integer)result);
        return returnObj;
     ......

根据前面的函数调用情况,我们其实可以看到,这个函数其实是对应的数据类型不同可以调用到不同的方法,比如字符串操作的startwith,日期函数对应的getYear,这个函数是可以根据类型来适配的。

我们操作一把:对应日期类型提前年月日的操作:

select  Reflect2(ts, "getYear"),
       reflect2(ts, "getMonth"),
       reflect2(ts, "getDay"),
       reflect2(ts, "getHours"),
       reflect2(ts, "getMinutes"),
       reflect2(ts, "getSeconds")
     from (select cast('2013-02-15 19:41:20' as timestamp) ts ) t; 
     
 113     1       5       19      41      20  

这里发现了我们的2013的年结果是113,月份是1,这个我们也是要看源码去解释:

我们看到年份其实是从1900开始计算的,月份其实是从0开始算的,计算器一点,我们没问题。

再来一个字符串替换操作:

select     reflect2("原始值[val]", "replace", "val", "新值") 
原始值新值

java_method

反射函数最后的一个函数,我们还是按照老路子去找,我们找到测试的代码:

SELECT java_method("java.lang.String", "valueOf", 1),
       java_method("java.lang.String", "isEmpty"),
       java_method("java.lang.Math", "max", 2, 3),
       java_method("java.lang.Math", "min", 2, 3),
       java_method("java.lang.Math", "round", 2.5D),
       round(java_method("java.lang.Math", "exp", 1.0D), 6),
       java_method("java.lang.Math", "floor", 1.9D)
FROM src tablesample (1 rows);

这个看了之后发现好像和reflect也没啥差别啊,我们只能心里觉得一样,但是总每个说服力,我们继续寻寻觅觅,发现这么一句话:

这架势,百度有道谷歌啥的通通来一遍,我们java_method和reflect其实是同义词的概念,我摸一下注册代码,发生其实对应的实现类其实就是同一个!

不用看了,玩跑跑去~

目录
相关文章
|
1月前
|
SQL 分布式计算 Hadoop
Hadoop-14-Hive HQL学习与测试 表连接查询 HDFS数据导入导出等操作 逻辑运算 函数查询 全表查询 WHERE GROUP BY ORDER BY(一)
Hadoop-14-Hive HQL学习与测试 表连接查询 HDFS数据导入导出等操作 逻辑运算 函数查询 全表查询 WHERE GROUP BY ORDER BY(一)
41 4
|
1月前
|
SQL
Hadoop-14-Hive HQL学习与测试 表连接查询 HDFS数据导入导出等操作 逻辑运算 函数查询 全表查询 WHERE GROUP BY ORDER BY(二)
Hadoop-14-Hive HQL学习与测试 表连接查询 HDFS数据导入导出等操作 逻辑运算 函数查询 全表查询 WHERE GROUP BY ORDER BY(二)
35 2
|
6月前
|
SQL HIVE
hive高频函数(一)
hive高频函数(一)
56 0
|
2月前
|
SQL JavaScript 前端开发
Hive根据用户自定义函数、reflect函数和窗口分析函数
Hive根据用户自定义函数、reflect函数和窗口分析函数
35 6
|
6月前
|
SQL XML JSON
Hive函数全解——思维导图 + 七种函数类型
Hive函数全解——思维导图 + 七种函数类型
134 2
Hive函数全解——思维导图 + 七种函数类型
|
6月前
|
SQL 分布式计算 HIVE
Hive Cli / HiveServer2 中使用 dayofweek 函数引发的BUG!
在Hive 3.1.2和Spark 3.0.2集群环境中,遇到`dayofweek`函数bug。当`create_date`为字符串类型时,`dayofweek`函数结果错位。修复方法是将`create_date`转换为`date`类型。在Spark SQL中,原始代码能正常运行,未出现此问题。因此建议在Hive中使用转换后的日期类型以避免错误。
75 4
|
6月前
|
SQL HIVE
【Hive SQL】字符串操作函数你真的会用吗?
本文介绍了SQL中判断字符串是否包含子串的几种方法。`IN`函数判断元素是否完全等于给定元素组中的某项,而非包含关系。`INSTR`和`LOCATE`函数返回子串在字符串中首次出现的位置,用于检测是否存在子串。`SUBSTR`则用于提取字符串的子串。`LIKE`用于模糊匹配,常与通配符配合使用。注意`IN`并非用于判断子串包含。
435 3
|
6月前
|
SQL 缓存 Java
Hive 之 UDF 运用(包会的)
Hive的UDF允许用户自定义数据处理函数,扩展其功能。`reflect()`函数通过Java反射调用JDK中的方法,如静态或实例方法。例如,调用`MathUtils.addNumbers()`进行加法运算。要创建自定义UDF,可以继承`GenericUDF`,实现`initialize`、`evaluate`和`getDisplayString`方法。在`initialize`中检查参数类型,在`evaluate`中执行业务逻辑。最后,打包项目成JAR,上传到HDFS,并在Hive中注册以供使用。
150 2
|
6月前
|
SQL HIVE 数据格式
Hive高频函数(二)
Hive高频函数(二)
44 0
|
6月前
|
SQL 数据采集 数据挖掘
大数据行业应用之Hive数据分析航班线路相关的各项指标
大数据行业应用之Hive数据分析航班线路相关的各项指标
191 1