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. 不能在具有唯一索引“IX_******”的对象“dbo.****”中插入重复键的行。重复键值为 (110, 372000, 2)。

    当尝试插入数据,或者更新某个表的时候出现 不能在具有唯一索引“IX_******”的对象“dbo.****”中插入重复键的行.重复键值为 (110, 372000, 2). 遇到这个问题的时候,请找到 ...

  2. Spring核心思想——IOC和DI

    基本概念 IOC是什么?     IOC(Inversion of Control)控制反转,IOC是一种新的Java编程模式,目前很多轻量级容器都在广泛使用的模式. IOC解决了什么问题?      ...

  3. L162

    More than 250 corporate signatories joined together to try and deal with plastic pollution in an ann ...

  4. debug运行java程序报错

    debug运行java程序报错 ERROR: transport error 202: connect failed: Connection timed out ERROR: JDWP Transpo ...

  5. Shell 命令行求两个文件每行对比的相同内容

    Shell 命令行求两个文件每行对比的相同内容 遇到的一个实际问题是,2017年08月01日起,所有未经实名的域名,全部停止解析.而我手上有不少域名,其中很多都是没有实名的.但我不知道哪些实名了,哪些 ...

  6. 如何自定义TFS中工作项的字段20141010

    如何自定义TFS中工作项的字段 我们以VS2013为例,TFS也是2013版本的: 1. 安装小插件 需要安装Visual Studio Team Foundation Server 2013 Pow ...

  7. ranch分析学习(一)

    Ranch 是一个tcp处理的程序框架.官方的解释  Ranch is a socket acceptor pool for TCP protocols. 主要目的是提供一个方便,易用,高效,稳定的t ...

  8. 逻辑回归 logistic regression(1)逻辑回归的求解和概率解释

    本系列内容大部分来自Standford公开课machine learning中Andrew老师的讲解,附加自己的一些理解,编程实现和学习笔记. 第一章 Logistic regression 1.逻辑 ...

  9. 线性回归 Linear regression(2)线性回归梯度下降中学习率的讨论

    这篇博客针对的AndrewNg在公开课中未讲到的,线性回归梯度下降的学习率进行讨论,并且结合例子讨论梯度下降初值的问题. 线性回归梯度下降中的学习率 上一篇博客中我们推导了线性回归,并且用梯度下降来求 ...

  10. 自己理解的java工厂模式,希望对大家有所帮助

    [http://www.360doc.com/content/11/0824/17/3034429_142983837.shtml] 这两天突然想学学java源代码,不过看到一篇文章说看java源代码 ...