
# 创建Hive用户自定义函数
#### 操作场景
当Hive的内置函数不能满足需要时，可以通过编写用户自定义函数UDF（User-Defined Functions）插入自己的处理代码并在查询中使用它们。本文为您介绍自定义函数的开发和运行。
#### Hive UDF介绍
表1Hive UDF介绍 
| UDF分类                                         | 说明                                                             |
|:---|:---|
| UDF（User-Defined Functions）                   | 自定义标量函数，其输入与输出是一对一的关系，即读入一行数据，写出一条输出值。                         |
| UDAF（User-Defined Aggregating Functions）      | 自定义聚合函数，其输入与输出是多对一的关系，即将多条输入记录聚合成一条输出值，可以与SQL中的Group By语句联合使用。 |
| UDTF（User-Defined Table-Generating Functions） | 自定义表值函数，用来解决一次函数调用输出多行数据场景的，也是唯一一个可以返回多个字段的自定义函数。              |
   
按使用方法，UDF有如下分类：
- 临时函数，只能在当前会话使用，重启会话后需要重新创建。
- 永久函数，可以在多个会话中使用，不需要每次创建。
 
#### 约束与限制
- 用户自定义函数需要用户控制函数中变量的内存、线程等资源的占用，如果控制不当可能会导致内存溢出、CPU使用高等问题。
- 若集群开启了Ranger鉴权，需要关闭Ranger鉴权后才能使用Python的UDF函数。关闭Ranger鉴权具体操作请参见[停用Ranger鉴权](https://support.huaweicloud.com/usermanual-mrs/mrs_01_300015.html#section2)。
- MRS 3.3.0-LTS及之后版本：
  - 删除UDF 当存在多个HiveServer时，如果连接其中一个HiveServer删除了自定义UDF，连接该HiveServer执行已删除的UDF时将返回不存在该UDF。但是其它的HiveServer由于缓存依旧可以访问已删除的UDF，需要连接每个HiveServer执行**reload function**刷新UDF缓存或重启HiveServer才能同步删除UDF。
    
  
  - 修改UDF 当修改自定义UDF的逻辑时，建议修改后的Jar包与修改前的Jar包在HDFS上的路径保持不变，此时只需要重新建立客户端连接即可以访问修改后的UDF。 如果Jar包的HDFS路径发生变化，需要连接每个HiveServer执行**reload function**刷新UDF缓存或重启HiveServer使修改的UDF生效。
    
   
 
 #### 步骤一：开发UDF
本示例中以编写一个名称为"AddDoublesUDF"的UDF为例，说明UDF的编写和使用方法。
"AddDoublesUDF"主要用来对两个及多个浮点数进行相加，在该样例中可以掌握如何编写和使用UDF。且需注意：
- 一个普通UDF必须继承自"org.apache.hadoop.hive.ql.exec.UDF"。
- 一个普通UDF必须至少实现一个evaluate()方法，evaluate函数支持重载。
- 开发自定义函数需要在工程中添加"hive-exec-\*.jar"依赖包，可从Hive服务的安装目录下获取，例如在"${BIGDATA_HOME}/components/FusionInsight_HD_\*/Hive/disaster/plugin/lib/"目录下获取。
- MRS 3.6.0-LTS及之后版本，Hive SQL运行的MapReduce作业默认使用JDK 8，因此建议使用JDK 8编译Hive UDF Jar包；如果使用JDK 17或JDK 21编译，则需在UDF样例的"pom.xml"文件的**properties**中新增"\<maven.compiler.target\>1.8\</maven.compiler.target\>"配置，且不能包含JDK 17或JDK 21新语法。
以下为"AddDoublesUDF"样例代码说明，其中，xxx通常为程序开发的组织名称。
```
package com.xxx.bigdata.hive.example.udf;
import org.apache.hadoop.hive.ql.exec.UDF;
public class AddDoublesUDF extends UDF { 
 public Double evaluate(Double... a) { 
    Double total = 0.0; 
    // 处理逻辑部分. 
    for (int i = 0; i < a.length; i++) 
      if (a[i] != null) 
        total += a[i]; 
    return total; 
  } 
}
```
将以上样例程序打包成"AddDoublesUDF.jar"（具体操作请参见[Hive开发指南](https://support.huaweicloud.com/devg-lts-mrs/mrs_07_110000.html)）。
#### 步骤二：创建执行UDF函数的用户
1. 使用**admin**用户登录Manager界面，选择"集群 \> 集群属性"，查看集群的"认证模式"并记录。
2. 选择"集群 \> 服务 \> Hive"，单击页面右上角的"更多"查看Hive是否启用Ranger鉴权。
3. 选择"系统 \> 权限 \> 用户"，单击"添加用户"，配置以下参数并单击"确定"，创建执行自定义函数的用户。
   
   表2添加用户 
   | 参数    | 示例                                  | 参数说明                                     |
   |:---|:---|:---|
   | 用户名   | **test**                            | 输入自定义用户名称。                               |
   | 用户类型  | **人机**                              | 设置"用户类型"，包括"人机"和"机机"用户。                  |
   | 密码    | *xxx*                               | 输入用户对应的密码。                               |
   | 确认新密码 | *xxx*                               | 再次输入用户对应的密码。                             |
   | 用户组   | 单击"添加"，选择"hive"和"hadoop"用户组并单击"确定"。 | 根据业务实际需要，在"用户组"，单击"添加"，选择一个或多个用户组添加到列表中。 |
      
   
   
4. 根据集群的认证模式及是否启用Ranger鉴权为新创建的用户赋权： 
   - 集群的"认证模式"为"安全模式"：
     - "启用Ranger鉴权"按钮置灰（Hive已启用Ranger鉴权），执行[5]。
     
     - "停用Ranger鉴权"按钮置灰（Hive未启用Ranger鉴权），执行[6]。
      
   
   - 集群的"认证模式"为"普通模式"：
     - "启用Ranger鉴权"按钮置灰（Hive已启用Ranger鉴权），执行[5]。
     
     - "停用Ranger鉴权"按钮置灰（Hive未启用Ranger鉴权），操作结束。
      
   
   
   
   
5. Hive使用Ranger鉴权，需使用Ranger管理员用户（安全模式集群为**rangeradmin** ，普通模式集群为**admin** ）登录Ranger管理界面为用户添加Hive权限控制策略。
   
   1. 选择"集群 \> 服务 \> Ranger"，单击"Ranger Web UI"右侧的超链接登录Ranger WebUI页面。
   
   2. 安全模式集群需单击页面右上角的用户名，在下拉框中单击"Log Out"退出当前用户，使用**rangeradmin**用户重新登录Ranger管理界面。
   
   3. 在首页中单击"HADOOP SQL"区域的组件插件名称如"Hive"。
   
   4. 在"Access"页签单击"Add New Policy"，配置以下参数并单击"Add"。
      表3新增Hive权限控制策略 
      | 参数               | 示例        | 参数说明                                                                                                                                                                                                                                                                                                                        |
      |:---|:---|:---|
      | Policy Name      | test_hive | 输入自定义策略名称，不能与本服务内其他策略名称重复。                                                                                                                                                                                                                                                                                                  |
      | database         | default   | 将适用该策略的Hive数据库名称。 - 永久函数：配置要添加函数的数据库名称，例如：default。  - 临时函数：将"database"切换为"global"，并配置具体的函数名或设置为"**\***"。                               |
      | table            | -         | 将适用该策略的Hive表名称。需切换为"udf"，并配置具体的函数名或设置为"**\***"。临时函数无需配置该参数。                                                                                                                                                                                                                                                                 |
      | Allow Conditions | -         | 策略允许条件，配置本策略内允许的权限及例外。在"Select User"列选择新增的用户，在"Permissions"新增以下权限： - 永久函数：根据实际业务需求进行授权，例如，可新增"create"、"select"和"drop"权限。  - 临时函数：添加"Temporary UDF Admin"权限。   |
         
      
   
   
   
   
6. Hive使用Manager角色鉴权，需创建具有Hive管理员权限的用户才能执行永久函数和临时函数。
   
   1. 在Manager页面首页，选择"系统 \> 权限 \> 角色"，单击"添加角色"，配置以下参数并单击"确定"：
      - 角色名称：填写角色名称，例如：test_role。
      
      - 配置资源权限：在"配置资源权限"列表中单击"*待操作的集群名称* \> Hive"，勾选"Hive管理员权限"。
       
   
   2. 单击"用户"，单击[3]新创建的用户所在行的"修改"。
   
   3. 在修改用户页面，单击"角色"右侧的添加，添加新创建的具有Hive管理员权限的角色，单击"确定"。
   
   
   
   
 
#### 步骤三：运行UDF
1. 将[步骤一：开发UDF]打包的"AddDoublesUDF.jar"上传至客户端安装节点，例如"opt"目录下。
2. 以客户端安装用户登录安装客户端的节点，上传[1]中的"AddDoublesUDF.jar"到HDFS指定目录下，例如"/user/hive_examples_jars"，且创建函数的用户与使用函数的用户都需要具有该文件的可读权限。
   
   1. 切换至客户端安装目录并配置环境变量： 切换至客户端安装目录：
      ```
      cd 客户端安装目录
      ```
      配置环境变量：
      ```
      source bigdata_env
      ```
      
   
   2. 认证用户。
      - 集群已开启Kerberos认证（安全模式）：
        ```
        kinit 业务用户
        ```
        
      
      - 集群未开启Kerberos认证（普通模式）：
        ```
        export HADOOP_USER_NAME=业务用户
        ```
        
       
   
   3. 上传UDF Jar包至HDFS目录中：
      ```
      hdfs dfs -put /opt /user/hive_examples_jars
      ```
      修改权限：
      ```
      hdfs dfs -chmod 777 /user/hive_examples_jars
      ```
      
   
   
   
   
3. 登录Hive客户端。 
   - 集群已开启Kerberos认证（安全模式），执行如下命令：
     ```
     beeline
     ```
     如果用户绑定了Hive管理员角色，在每个beeline的维护操作会话中，都需要执行以下命令切换成**admin**角色再执行后续操作：
     ```
     set role admin;
     ```
     
   
   - 集群未开启Kerberos认证（普通模式），执行如下命令：
     ```
     beeline -n Hive业务用户
     ```
     
   
   
   
   
4. 在Hive Server中执行以下命令创建自定义函数： 
   - 创建永久函数：
     ```
     CREATE FUNCTION addDoubles AS 'com.xxx.bigdata.hive.example.udf.AddDoublesUDF' using jar 'hdfs://hacluster/user/hive_examples_jars/AddDoublesUDF.jar';
     ```
     其中*addDoubles* 是该函数的名称，用于SELECT查询中使用；*xxx*通常为程序开发的组织名称。
     
   
   
   
   - 创建临时函数：
     ```
     CREATE TEMPORARY FUNCTION addDoubles AS 'com.xxx.bigdata.hive.example.udf.AddDoublesUDF' using jar 'hdfs://hacluster/user/hive_examples_jars/AddDoublesUDF.jar';
     ```
     - *addDoubles*是该函数的名称，用于SELECT查询中使用。
     
     - 关键字TEMPORARY说明该函数只在当前这个Hive Server的会话过程中定义使用。
      
   
   
   
   
5. 在Hive Server中执行以下命令使用该函数： 
   ```
   SELECT addDoubles(1,2,3);
   ```
   如果重新连接客户端再使用函数出现"\[Error 10011\]"错误，可执行**reload function;**命令后再使用该函数。例如，报错信息如下：
   ```
   Error: Error while compiling statement: FAILED: SemanticException [Error 10011]: Line 1:7 ...
   ```
   
   
6. 在Hive Server中执行以下命令删除该函数： 
   ```
   DROP FUNCTION addDoubles;
   ```
   
   
 
#### 相关文档
- 如果在Hive客户端中使用Spark创建UDF函数或多个HiveServer之间使用UDF报错"ERROR 10011"、"invalid function"，处理该故障的具体操作请参见[使用UDF函数时提示"Invalid function"](https://support.huaweicloud.com/trouble-mrs/mrs_03_0173.html)。
- 创建Hive永久UDF函数时报错用户权限不足，处理该故障的具体操作请参见[在beeline客户端创建UDF时报错](https://support.huaweicloud.com/trouble-mrs/mrs_03_0166.html)。
- 如需在Hive自定义函数中操作本地文件，具体操作请参见[如何在Hive自定义函数中操作本地文件](https://support.huaweicloud.com/cmpntguide-mrs/mrs_01_1755.html)。
- 如需删除所有HiveServer中的永久函数，具体操作请参见[如何删除所有HiveServer中的永久函数](https://support.huaweicloud.com/cmpntguide-mrs/mrs_01_1753.html)。
 
