Hive 内置了很多函数,但是有些特殊场景下是没有办法满足的。可以使用基于Java的用户定义函数(UDF)扩展配置单元SQL,并从配置单元查询调用UDF。

用Java实现Hive的UDF非常简单,只需要编写Java代码,打包成JAR包,最后在Hive中注册就可以使用。

本文演示如何创建一个Hive UDF,以及如何注册使用。

Java编写Hive的UDF代码很简单,只需要做两件事:

  • 第一,继承UDF类。
  • 第二,实现evaluate( )方法。

    UDF实现的功能在evaluate里实现。Hive根据类名来创建UDF,调用的时候根据evaluate参数来调用不同的方法,实现不同的功能。

准备环境

首先准备开发环境

  • JDK 8
  • Apache Maven 3.3.9
  • IntelliJ IDEA

创建一个 Maven 项目,File > New > Project > Maven,点击 Enable Auto-Import,修改pom.xml文件如下:

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  5. <modelVersion>4.0.0</modelVersion>
  6. <groupId>com.data.hive</groupId>
  7. <artifactId>hive_udf</artifactId>
  8. <version>1.0-SNAPSHOT</version>
  9. <properties>
  10. <project.build.sourceEncoding>UTF8</project.build.sourceEncoding>
  11. <hadoop.version>2.7.2</hadoop.version>
  12. <hive.version>2.0.1</hive.version>
  13. </properties>
  14. <repositories>
  15. <!--加入Hadoop原生态的maven仓库的地址-->
  16. <repository>
  17. <id>Apache Hadoop</id>
  18. <name>Apache Hadoop</name>
  19. <url>https://repo1.maven.org/maven2/</url>
  20. </repository>
  21. </repositories>
  22. <dependencies>
  23. <!--添加hadoop依赖-->
  24. <dependency>
  25. <groupId>org.apache.hadoop</groupId>
  26. <artifactId>hadoop-common</artifactId>
  27. <version>${hadoop.version}</version>
  28. </dependency>
  29. <!--添加hive依赖-->
  30. <dependency>
  31. <groupId>org.apache.hive</groupId>
  32. <artifactId>hive-exec</artifactId>
  33. <version>${hive.version}</version>
  34. </dependency>
  35. </dependencies>
  36. <build>
  37. <plugins>
  38. <plugin>
  39. <groupId>org.apache.maven.plugins</groupId>
  40. <artifactId>maven-shade-plugin</artifactId>
  41. <version>2.4.3</version>
  42. <executions>
  43. <execution>
  44. <phase>package</phase>
  45. <goals>
  46. <goal>shade</goal>
  47. </goals>
  48. <configuration>
  49. <filters>
  50. <filter>
  51. <artifact>*:*</artifact>
  52. <excludes>
  53. <exclude>META-INF/*.SF</exclude>
  54. <exclude>META-INF/*.DSA</exclude>
  55. <exclude>META-INF/*.RSA</exclude>
  56. </excludes>
  57. </filter>
  58. </filters>
  59. <transformers>
  60. <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
  61. <mainClass></mainClass>
  62. </transformer>
  63. </transformers>
  64. </configuration>
  65. </execution>
  66. </executions>
  67. </plugin>
  68. </plugins>
  69. </build>
  70. </project>

编写代码

这里是一个 Hive UDF,它使用一个长参数并返回其十六进制表示。

  1. package com.cuteximi.udf
  2. import org.apache.hadoop.hive.ql.exec.UDF
  3. import org.apache.hadoop.io.LongWritable
  4. // This UDF takes a long integer and converts it to a hexadecimal string.
  5. class ToHex extends UDF {
  6. def evaluate(n: LongWritable): String = {
  7. Option(n)
  8. .map { num =>
  9. // Use Scala string interpolation. It's the easiest way, and it's
  10. // type-safe, unlike String.format().
  11. f"0x${num.get}%x"
  12. }
  13. .getOrElse("")
  14. }
  15. }

部署

官方提供了两种部署 UDF 的方式:

  • 临时部署(Temporary Functions)
  • 永久部署(Permanent Functions)

两者的区别在于:临时部署的方式,只会在当前 Session 下有效并可用;永久部署的方式,在部署成功后任何一个 Hive 客户端(重新启动的 Hive 客户端,已经启动的客户端需要重新加载)都可以使用。

(1) 临时部署

这个是最常见的 Hive 使用方式,通过 hive 命令来完成 UDF 的部署;

  1. hive> add jar /path/to/local.jar;
  2. hive> create temporary function to_hex as 'com.cuteximi.udf.ToHex';

(2) 永久部署

这种方式是 hive-0.13 版本以后开始支持的注册方法;

  1. hive> create function to_hex
  2. hive> as 'com.cuteximi.udf.ToHex'
  3. hive> using jar 'hdfs:///path/to/hdfs.jar';

需要注意两点:1 如果方法前面不指定数据库,会默认创建在当前数据库里面。

在一个配CLI会话中创建永久函数可能不会反映在配置单元server2或其他配置单元CLI会话中(如果它们是在创建函数之前启动的)。

在HiveServer2或HiveCLI会话中发出RELOAD函数将允许它获取对永久函数的任何更改,这些更改可能是由不同的HiveCLI会话完成的。由于向后兼容的原因,重新加载函数;具体见讨论:HIVE-2573

常用命令


  1. -- 查看所有函数(内置函数+自定义函数)
  2. show functions;
  3. -- 查看某个函数的使用说明
  4. describe function function_name;
  5. -- 创建临时自定义函数
  6. create temporary function function_name as class_name;
  7. -- 删除临时自定义函数
  8. drop temporary function [if exists] function_name;
  9. -- 创建永久自定义函数
  10. create function [db_name.]function_name as class_name
  11. [using jar|file|archive 'file_uri' [, jar|file|archive 'file_uri'] ];
  12. -- 删除永久自定义函数
  13. drop function [if exists] function_name;
  14. -- 重载函数
  15. reload function;


参考

原文

https://mp.weixin.qq.com/s?__biz=MzU3NDUzMjA0MQ==&mid=2247483755&idx=1&sn=c315fdc6ffc750957e054244ffdf5640&chksm=fd31b1cdca4638db5da100ae02c99005ed3d4c4be6b1ecc4e2a8ed2c70672738f6fdf8d0921c&token=1615649374&lang=zh_CN#rd