Hive中的自定义函数允许用户扩展HiveQL,是一个非常强大的功能。Hive中具有多种类型的用户自定义函数。show functions命令可以列举出当前Hive会话中的所加载进来的函数,包括内置的以及用户加载的函数。

函数都有自身的使用文档,使用describe function命令就可以展示对应函数基本介绍。

标准函数UDF

用户自定义函数指的是一行数据中的一列或是多列数据作为参数然后返回结果是一个值的函数。这里用一个例子作为说明,我们当前有些数据表中存储的时间戳是以秒为单位的long值,如果想将这个long值转换为当天的hour值,就需要写一个UDF(尽管这个需求可以通过Hive中的标准函数解决...但我们举个例子)。

简单的UDF编写,直接继承org.apache.hadoop.hive.ql.exec.UDF,并实现evaluate方法,其中UDF抽象类中并没有严格要求evaluate的方法签名,这意味着可以使用Java中的重载,这样在实际使用时会根据传输参数的类型选择合适的方法;对于每行输入都会调用到evaluate函数,处理后的结果返回给Hive。

public class ToHourFunction extends UDF{

    public String evaluate(String timeMillis) {
long longTimeMillis = Long.parseLong(timeMillis);
Date date = new Date(longTimeMillis * 1000L);
return String.format("%tk", date);
}
}

对于自定的UDF,为了让其他人在使用时能够得到一些帮助信息,最好添加@Description注解。注解中包含了这个函数的文档说明,用户也需要这个注解来说明自定义UDF如何使用,比如添加下面的注解:

@Description(name = "to_hour", value = "_FUNC_(x) - return long time millis(plus 1000) to current hour",
extended = "Example: to_hour(123232343) ")

value中的_FUNC_会被替换成用户为这个函数定义的“临时”函数名称,当添加这个jar包,并添加这个自定义函数,将其命名为to_hour

create temporary function to_hour as 'test.udf.ToHourFunction';

添加完成后,执行show functions命令就会额外添加一个我们的自定义函数,使用describe function to_hour能够显示出函数的具体使用方法(@Description中的内容)

to_hour(x) - return long time millis(plus 1000) to current hour

通过使用describe function extended to_hour可以显示@Descrption中的extended属性内容:

Example: to_hour(123232343)

除了UDF类,Hive还提供了一个对应的称为GenericUDF的类,GenericUDF是更为复杂的抽象概念,但是支持更好的null值处理。在Hive中本身就有很多函数是用GenericUDF实现的,我们可以参考他们的写法,比如GenericUDFAbs就是对一些基本的数据类型(SHORT/BYTE/INT/LONG/DOUBLE/FLOAT/STRING/DECIMAL)取绝对值的函数。

比如上面同样的to_hour函数,我们可以用GenericUDF重写一遍。继承GenericUDF函数之后,需要实现三个方法。

首先,initialize方法作为初始化使用,这个方法的目标是确定函数的参数类型,如果参数的数量以及类型不合法,要抛出异常以给用户必要的提示。to_hour方法中,我们需要界定输入参数必须为long类型,参数数量为1个,输出的结果为int类型。

    private IntWritable resultInt = new IntWritable();
private ObjectInspectorConverters.Converter inputConverter; @Override
public ObjectInspector initialize(ObjectInspector[] arguments) throws UDFArgumentException {
if (arguments.length != 1) {
throw new UDFArgumentLengthException(
"to_hour requires 1 argument, got " + arguments.length);
} if (arguments[0].getCategory() != ObjectInspector.Category.PRIMITIVE) {
throw new UDFArgumentException(
"to_hour only takes primitive types, got " + arguments[0].getTypeName());
}
PrimitiveObjectInspector argumentOIs = (PrimitiveObjectInspector) arguments[0];
PrimitiveObjectInspector.PrimitiveCategory inputType = argumentOIs.getPrimitiveCategory();
if (inputType != PrimitiveObjectInspector.PrimitiveCategory.LONG) {
throw new UDFArgumentTypeException(0, "Argument type should be long");
}
inputConverter = ObjectInspectorConverters
.getConverter(arguments[0], PrimitiveObjectInspectorFactory.writableLongObjectInspector);
return PrimitiveObjectInspectorFactory.writableIntObjectInspector;
}

方法evaluate的输入是一个DeferredObject[],通过initialize方法初始化的inputConverter将DeferredObject转换成对应的Writable对象,这一步中如果输入参数类型可变的话,这个inputConverter的意义就比较重大了,这一点请参考Hive中Abs函数的实现。后面就是将这个数据写到可重用的IntWritable对象中。

@Override
public Object evaluate(DeferredObject[] arguments) throws HiveException {
Object valueObj = arguments[0].get();
if (valueObj == null) {
return null;
}
valueObj = inputConverter.convert(valueObj);
long mills = ((LongWritable) valueObj).get() * 1000L;
String hourString = String.format("%tk", new Date(mills));
int hour = Integer.parseInt(hourString);
resultInt.set(hour);
return resultInt;
}

最后一个需要实现的方法是getDisplayString(),用在Hadoop Task内部,在使用此函数时显示调试信息。

@Override
public String getDisplayString(String[] children) {
StringBuilder sb = new StringBuilder();
sb.append("to_hour(");
if (children.length > 0) {
sb.append(children[0]);
for (int i = 1; i < children.length; i++) {
sb.append(",");
sb.append(children[i]);
}
}
sb.append(")");
return sb.toString();
}

截止目前,我们写的函数都只能创建为temp函数,如果想加入到Hive本身作为系统的不变函数使用,就需要修改org.apache.hadoop.hive.ql.exec.FunctionRegistry中的static静态块,将我们的函数加入进去,并重新编译部署hive(当然比较麻烦,不过仅需要替换hive-exec-版本号.jar文件即可)。稍微简单并灵活的方法是,我们写一个公用的shell加载脚本,每个hiveql文件在头上手动加载这个脚本,将公用的函数库加入进去。

Hive中的用户自定义函数UDF的更多相关文章

  1. Hive中的用户自定义函数

    1.1 关于自定义函数 1)Hive 自带了一些函数,比如:max/min等,但是数量有限,自己可以通过自定义UDF来方便的扩展. 2)当Hive提供的内置函数无法满足你的业务处理需要时,此时就可以考 ...

  2. Hive 文件格式 & Hive操作(外部表、内部表、区、桶、视图、索引、join用法、内置操作符与函数、复合类型、用户自定义函数UDF、查询优化和权限控制)

    本博文的主要内容如下: Hive文件存储格式 Hive 操作之表操作:创建外.内部表 Hive操作之表操作:表查询 Hive操作之表操作:数据加载 Hive操作之表操作:插入单表.插入多表 Hive语 ...

  3. Spark SQL 用户自定义函数UDF、用户自定义聚合函数UDAF 教程(Java踩坑教学版)

    在Spark中,也支持Hive中的自定义函数.自定义函数大致可以分为三种: UDF(User-Defined-Function),即最基本的自定义函数,类似to_char,to_date等 UDAF( ...

  4. SparkSQL中的自定义函数UDF

    在Spark中,也支持Hive中的自定义函数.自定义函数大致可以分为三种: UDF(User-Defined-Function),即最基本的自定义函数,类似to_char,to_date等 UDAF( ...

  5. SQL Server在用户自定义函数(UDF)中使用临时表

    SQL Server在用户自定义函数中UDF使用临时表,这是不允许的. 有时是为了某些特殊的场景, 我们可以这样的实现: CREATE TABLE #temp (id INT) GO INSERT I ...

  6. 详解Spark sql用户自定义函数:UDF与UDAF

    UDAF = USER DEFINED AGGREGATION FUNCTION Spark sql提供了丰富的内置函数供猿友们使用,辣为何还要用户自定义函数呢?实际的业务场景可能很复杂,内置函数ho ...

  7. 样条函数后续(java)--可在hive中执行的函数

    之前写的样条插值算法只能在本地执行,但是我想要的是可在hive中执行的jar包,为了符合我的要求,经过痛苦.气愤.悲伤等一系列过程,终于实现了: 想要实现可在hive中执行的jar包,以下是具体步骤: ...

  8. hive中内置函数

    查看函数的详细使用方法 desc function extended 函数名 例如: 1).desc function extended locate locate(substr, str[, pos ...

  9. php中调用用户自定义函数的方法:call_user_func,call_user_func_array

    看UCenter的时候有一个函数call_user_func,百思不得其解,因为我以为是自己定义的函数,结果到处都找不到,后来百度了一下才知道call_user_func是内置函数,该函数允许用户调用 ...

随机推荐

  1. PostgreSQL CheckPoint设置(转)

    今天在研究checkpoint process的问题时,顺便复习了一下checkpoint设置问题,又有新的疑惑了. checkpoint又名检查点,在oracle中checkpoint的发生意味着之 ...

  2. Linux:expand命令详解

    expand 用于将文件的制表符[TAB]转换为空格,将结果显示到标准输出设备 语法 expand(选项)(file) 选项 -t<数字>:指定制表符所代表的空白字符的个数,而不使用默认的 ...

  3. 【SQL查询】分区查询Over

    1. Over介绍 Over为开窗函数.就是把满足条件的数据分成几个区域,每个区域可以通过像现实中的“窗口”来观察统计这些数据. over不能单独使用,要和分析函数:rank(), dense_ran ...

  4. Chrome浏览器优化技巧

    Chrome浏览器开发者工具Network窗口下,可以查看下载各组件所需的具体时间 根据上表进行简要分析—— Stalled(阻塞) 浏览器对同一个主机域名的并发连接数有限制,因此如果当前的连接数已经 ...

  5. asp.net button浏览器端事件和服务器端事件

    OnClientClick:触发浏览器端的响应,OnClick触发服务器端响应; 在服务器aspx.cs脚本中设置按钮属性: this.btnTest.Attributes["OnClick ...

  6. mysql创建的数据库在电脑什么位置?

    你可以在mysql 命令行里执行 show variables like '%datadir%'; 显示出你数据文件的路径,能找到以你创建的数据库的名字的文件夹了.

  7. Vim技能修炼教程(14) - 写个ex命令吧

    写个ex命令吧 我们第二节开始就写了语法高亮的插件.这一节,我们学习第二种插件的写法,就是写个我们自己的ex命令. 自定义ex命令的命令是:command,我们在~/.vim/下建立一个plugin目 ...

  8. ng-if 判断条件中不能 使用变量名字拼接,switch可以

  9. [Math]PHI, the golden ratio

    PHI, the golden ratio 黄金分割比 转载自 http://paulbourke.net/miscellaneous/miscnumbers/ 1. Definition 将一个线段 ...

  10. 【剑指offer】不使用新变量,交换两个变量的值,C++实现

    # 题目 不使用新变量,交换两个变量的值. # 思路 方法一:使用加减法操作,交换两个变量的值. A = A+B B = A-B A = A-B 方法二:使用异或运算,交换两个变量的值 A = A^B ...