大数据Hive中的UDF:自定义数据处理的利器(上)

打印 上一主题 下一主题

主题 891|帖子 891|积分 2673



  
1. 前言

在大数据技能栈中,Apache Hive 扮演着数据仓库的关键脚色,它提供了丰富的数据操作功能,并通过雷同于 SQL 的 HiveQL 语言简化了对 Hadoop 数据的处理。然而,内置函数库虽强大,却未必能满意全部特定的业务逻辑需求。此时,用户定义函数(User-Defined Functions,UDF)的重要性便凸显出来。
Hive UDF(User-Defined Function)是Hive中的一种扩展机制,它允许用户通过编写自定义的Java代码来扩展Hive的功能,实现Hive内置函数无法提供的一些特定数据处理逻辑。
2. UDF与宏及静态表的对比

除了UDF可以自定义输入和输出还有例如静态表,宏定义的方式也可以实现雷同的操作,举个例子:在数据中筛选出已达到退休年岁的员工。
   UDF 示例
  1. import org.apache.hadoop.hive.ql.exec.UDF;
  2. import org.apache.hadoop.io.Text;
  3. public class RetirementStatusUDF extends UDF {
  4.     public Text evaluate(int age) {
  5.         return new Text(age >= 60 ? "已达到退休年龄" : "未达到退休年龄");
  6.     }
  7. }
  8. -- 添加UDF的jar包到Hive
  9. ADD JAR /path/to/udf.jar;
  10. -- 创建临时函数
  11. CREATE TEMPORARY FUNCTION retirement_status AS 'com.example.RetirementStatusUDF';
  12. -- 使用UDF进行查询
  13. SELECT name, age, retirement_status(age) AS status
  14. FROM employee_static;
复制代码
  静态表
  1. CREATE TABLE employee_static (
  2.   age INT,
  3.   flag STRING -- 'retired' 或 'active'
  4. );
  5. -- 查询已达到退休年龄的员工
  6. SELECT a.*
  7. FROM employee_data a
  8. JOIN employee_static b
  9. ON a.age = b.age AND b.flag = 'retired';
复制代码
  宏定义
  1. drop temporary macro if exists get_retired;
  2. create temporary macro get_retired(age bigint)
  3. if (
  4.        age is not null,
  5.        case
  6.               when age >= 60 then '退休'
  7.               when age <= 60 then '未退休'
  8.               else null
  9.        end,
  10.        null
  11. );
复制代码
利用UDF(用户定义函数)的原因与宏和静态表的功能有所差别,它们各自适用于差别的场景和需求。以下是利用UDF的几个关键原因:
特性/方法UDF(用户定义函数)宏(Macro)静态表(Static Table)定义允许用户通过编写自定义的Java代码来扩展Hive的功能,实现特定的数据处理逻辑。在Hive中,宏是一种用户定义的快捷方式,用于封装一系列HiveQL语句,以便在查询中重复利用。预先定义和填充的数据集,其结构和内容在创建后通常保持稳固。利用场景适用于实行Hive内置函数不支持的特定数据处理逻辑,如复杂的业务规则或算法。重要用于简化和重用HiveQL查询语句,进步代码的可读性和易维护性。适用于存储已知的、稳固的数据集,供多次查询利用,无需每次重新计算。灵活性高,可以根据需求定制数据处理流程。中等,重要用于简化复杂的查询,但不具备动态处理能力。低,结构和内容一旦定义,通常不发生变化。性能可优化,Hive实行UDF时会举行优化,性能接近内置函数。取决于宏定义的查询的复杂性,可能进步或低沉性能。预先计算,查询时性能较高,得当重复查询雷同数据集。重用性高,一旦创建和注册,可以在差别的Hive会话中重复利用。高,宏可以定义一次并在多个查询中重复利用。中等,表结构和数据稳固,适用于重复查询雷同数据集的场景。实时性支持实时数据处理,每次调用UDF时根据输入动态实行计算。不直接支持实时数据处理,重要用于查询语句的封装。不支持实时数据处理,通常是预先计算和存储的。顺应性强,可以快速顺应新的数据处理需求。中等,必要修改宏定义以顺应新的需求。弱,结构和数据固定,不得当频繁变化的数据需求。示例应用用于实现如复杂数学计算、自定义字符串处理、数据清洗等。用于封装复杂的查询模板,如多步调的数据转换过程。用于存储设置数据、参考数据或不必要频繁更新的数据。 选择利用UDF、宏还是静态表应基于具体的业务需求、数据特性和性能考虑。每种方法都有其独特的优势和适用场景。
3. 深入明白UDF

Hive UDF可以分为三种重要类型:UDF、UDAF和UDTF。

  • UDF (User-Defined Function)

    • 标量函数,用于一对一(one-to-one)的映射,即对单个数据项举行操作并返回单个结果。
    • 例如,字符串处理(upper, substr)、数学计算(sqrt)、日期时间转换等。

  • UDAF (User-Defined Aggregate Function)

    • 聚合函数,用于多对一(many-to-one)的映射,即对多行数据举行聚合操作并返回单个结果。
    • 例如,自定义的求和(sum)、平均值(avg)、最大值(max)、最小值(min)等。

  • UDTF (User-Defined Table-Generating Function)

    • 表生成函数,用于一对多(one-to-many)的映射,即对单个数据项举行操作并返回多行结果。
    • 例如,explode函数可以将数组或Map类型的列拆分成多行。

种别简称全称描述示例UDFUser-Defined Function用于实现一对一的映射,即一个输入对应一个输出。将字符串转换为大写。UDAFUser-Defined Aggregate Function用于实现一对多的映射,即多个输入对应一个输出。计算某个字段的总和或平均值。UDTFUser-Defined Table-Generating Function用于实现一对多的行生成,即一个输入可以产生多行输出。将数组或映射类型的字段展开成多行数据。 这些UDF类型允许开发者根据特定的数据处理需求,编写和实现自定义的函数逻辑,从而扩展Hive的数据处理能力。通过利用UDF、UDAF和UDTF,用户可以在Hive中实现更加复杂和定制化的数据处理任务。
实现一个UDF通常涉及以下步调:

  • 编写UDF类:在Java中创建一个类,实现Hive UDF接口的相应方法。对于标量UDF,这通常是evaluate方法。
  • 编译与打包:将UDF类编译成Java字节码,并打包成JAR文件。
  • 上传JAR包:将JAR文件上传到HDFS或其他Hive可以访问的文件系统中。
  • 注册UDF:在Hive会话中利用ADD JAR和CREATE TEMPORARY FUNCTION命令注册UDF。
  • 利用UDF:在Hive查询中调用注册的UDF,就像调用内置函数一样。

4. 实现自定义UDF

在深入探究Hive UDF的实现之前,让我们首先确保开发环境的准备妥当。对于UDF的编写,保举利用Maven来设置Java项目,如许可以方便地管理依赖和构建过程。以下是设置Java开发环境的一个示例,包罗利用的版本信息和Maven设置:
   Apache Maven 3.9.6
Java version: 1.8.0_211,
  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>org.example</groupId>
  7.     <artifactId>project202401</artifactId>
  8.     <version>1.0-SNAPSHOT</version>
  9.     <properties>
  10.         <maven.compiler.source>8</maven.compiler.source>
  11.         <maven.compiler.target>8</maven.compiler.target>
  12.         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  13.         <hadoop.version>3.1.1.7.1.7.2000-305</hadoop.version>
  14.         <hive.version>3.1.3000.7.1.7.2000-305</hive.version>
  15.     </properties>
  16.     <dependencies>
  17.         <dependency>
  18.             <groupId>org.apache.hive</groupId>
  19.             <artifactId>hive-exec</artifactId>
  20.             <version>${hive.version}</version>
  21.             <scope>provided</scope>
  22.         </dependency>
  23.         <dependency>
  24.             <groupId>org.apache.hadoop</groupId>
  25.             <artifactId>hadoop-common</artifactId>
  26.             <version>${hadoop.version}</version>
  27.             <scope>provided</scope>
  28.         </dependency>
  29.         <dependency>
  30.             <groupId>org.junit.jupiter</groupId>
  31.             <artifactId>junit-jupiter</artifactId>
  32.             <version>5.10.1</version>
  33.             <scope>test</scope>
  34.         </dependency>
  35.     </dependencies>
  36.     <repositories>
  37.         <repository>
  38.             <id>central</id>
  39.             <name>Maven Central</name>
  40.             <url>https://repo1.maven.org/maven2/</url>
  41.         </repository>
  42.         <repository>
  43.             <id>cloudera</id>
  44.             <name>Cloudera Repository</name>
  45.             <url>https://repository.cloudera.com/artifactory/cloudera-repos/</url>
  46.         </repository>
  47.     </repositories>
  48. </project>
复制代码
下面是一个Hive UDF(用户定义函数)的示例,该UDF的作用是将传入的字符串转换为大写形式。我将对代码举行注释,并表明其工作流程:
  1. import org.apache.hadoop.io.Text;  // 引入Hadoop的Text类,用于处理字符串
  2. import org.apache.hadoop.hive.ql.exec.UDF;  // 引入Hive的UDF类
  3. @SuppressWarnings({"deprecation", "unused"})  // 忽略警告,例如未使用的警告或过时API的警告
  4. public class UpperCaseUDF extends UDF {  // 定义一个名为UpperCaseUDF的类,继承自UDF
  5.     /**
  6.      * 该方法重写了UDF类中的evaluate方法,是UDF的核心。
  7.      * 它接收一个Text类型的数据,然后返回转换为大写的Text类型数据。
  8.      *
  9.      * @param line Text类型的输入数据
  10.      * @return 转换为大写的Text类型的数据
  11.      */
  12.     public Text evaluate(final Text line) {
  13.         // 检查传入的Text是否为非空且内容不为空字符串
  14.         if (null != line && !line.toString().equals("")) {
  15.             // 将Text转换为String,并使用String的toUpperCase方法转换为大写
  16.             String str = line.toString().toUpperCase();
  17.             // 将大写字符串重新设置回Text对象,并返回
  18.             line.set(str);
  19.             return line;
  20.         } else {
  21.             // 如果传入的Text为null或空字符串,则返回一个新的空Text对象
  22.             return new Text();
  23.         }
  24.     }
  25. }
复制代码
在Hive的较新版本中,保举利用GenericUDF而不是直接继续UDF。以下是利用GenericUDF实现的UpperCaseUDF2的示例代码,以及对代码的具体表明和工作流程分析:
  1. import org.apache.hadoop.hive.ql.exec.UDFArgumentException;
  2. import org.apache.hadoop.hive.ql.metadata.HiveException;
  3. import org.apache.hadoop.hive.ql.udf.generic.GenericUDF;
  4. import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector;
  5. import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorFactory;
  6. import org.apache.hadoop.hive.serde2.objectinspector.primitive.StringObjectInspector;
  7. import org.apache.hadoop.io.Text;
  8. import org.apache.hadoop.hive.ql.udf.UDFType;
  9. @UDFType(deterministic = true, stateful = false) // 标注UDF的特性,确定性且无状态
  10. public class UpperCaseUDF2 extends GenericUDF { // 继承自GenericUDF
  11.     private StringObjectInspector inputOI; // 输入对象检查员,用于检查输入类型
  12.     private StringObjectInspector outputOI; // 输出对象检查员,用于定义输出类型
  13.     /**
  14.      * initialize方法在UDF首次执行时被调用,用于初始化UDF。
  15.      * @param arguments 传入的参数对象检查员数组
  16.      * @return 输出对象检查员
  17.      * @throws UDFArgumentException 如果输入参数不符合预期,抛出异常
  18.      */
  19.     @Override
  20.     public ObjectInspector initialize(ObjectInspector[] arguments) throws UDFArgumentException {
  21.         // 确保传入的参数是字符串类型
  22.         if (arguments == null || arguments.length == 0) {
  23.             throw new UDFArgumentException("arguments array is null or empty.");
  24.         }
  25.         if (!(arguments[0] instanceof StringObjectInspector)) {
  26.             // 如果不是字符串类型,抛出Hive异常
  27.             throw new UDFArgumentException("The input to UpperCaseUDF2 must be a string");
  28.         }
  29.         // 将输入参数的对象检查员赋值给局部变量
  30.         inputOI = (StringObjectInspector) arguments[0];
  31.         // 定义输出对象检查员为可写的字符串对象检查员
  32.         outputOI = PrimitiveObjectInspectorFactory.writableStringObjectInspector;
  33.         // 返回输出对象检查员
  34.         return outputOI;
  35.     }
  36.     /**
  37.      * evaluate方法定义了UDF的实际逻辑,即如何将输入转换为输出。
  38.      * @param arguments 包含延迟计算的输入对象的数组
  39.      * @return 转换后的大写文本
  40.      * @throws HiveException 如果在执行过程中遇到Hive异常
  41.      */
  42.     @Override
  43.     public Object evaluate(DeferredObject[] arguments) throws HiveException {
  44.         // 从延迟对象中获取输入字符串
  45.         Text line = (Text) arguments[0].get();
  46.         // 如果输入不为空,则转换为大写
  47.         if (line != null && !line.toString().isEmpty()) {
  48.             return new Text(line.toString().toUpperCase());
  49.         }
  50.         // 如果输入为空,返回空字符串
  51.         return new Text();
  52.     }
  53.     /**
  54.      * getDisplayString方法返回UDF的可读字符串表示,用于Hive日志和解释计划。
  55.      * @param strings 输入参数的字符串表示,通常由Hive自动生成
  56.      * @return UDF的可读字符串表示
  57.      */
  58.     @Override
  59.     public String getDisplayString(String[] strings) {
  60.         // 返回UDF的名称,用于解释计划和日志
  61.         return "UpperCaseUDF2()";
  62.     }
  63. }
复制代码
  1. add jar URL/project202401-1.0-SNAPSHOT.jar;
  2. create temporary function UpperCaseUDF as 'com.xx.hive.udf.UpperCaseUDF';
  3. select UpperCaseUDF('Hive Is Fun') a ;
复制代码
  HIVE IS FUN
  通过以上步调,我们可以或许创建出高效、可靠的Hive UDF,以满意特定的数据处理需求。UDF的开发不仅必要关注功能的实现,还要器重性能优化和代码的可维护性。正确地利用UDF可以显著提升数据处理的效率,为用户提供强大的数据操作能力。
   因为篇幅有限,背面两种自定义UDF,会在下一篇博文展开叙述。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

罪恶克星

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表