
# 在Spark SQL作业中使用UDF
#### 操作场景
DLI支持用户使用Hive UDF（User Defined Function，用户定义函数）进行数据查询等操作，UDF只对单行数据产生作用，适用于一进一出的场景。
#### 约束限制
- 在DLI Console上执行UDF相关操作时，需要使用自建的SQL队列。
- 跨账号使用UDF时，除了创建UDF函数的用户，其他用户如果需要使用时，需要先进行授权才可使用对应的UDF函数。授权操作参考如下： 登录DLI管理控制台，选择" 数据管理 \> 程序包管理"页面，选择对应的UDF Jar包，单击"操作"列中的"权限管理"，进入权限管理页面，单击右上角"授权"，勾选对应权限。
  
- 自定义函数中引用static类或接口时，必须要加上"try catch"异常捕获，否则可能会造成包冲突，导致函数功能异常。
 
#### 环境准备
在进行UDF开发前，请准备以下开发环境。
表1UDF开发环境 
| 准备项                | 说明                                           |
|:---|:---|
| 操作系统               | Windows系统，支持Windows7以上版本。                    |
| 安装JDK              | JDK使用1.8版本。                                  |
| 安装和配置IntelliJ IDEA | IntelliJ IDEA为进行应用开发的工具，版本要求使用2019.1或其他兼容版本。 |
| 安装Maven            | 开发环境的基本配置。用于项目管理，贯穿软件开发生命周期。                 |
   
#### 开发流程
DLI下UDF函数开发流程参考如下：
图1开发流程   
![](https://support.huaweicloud.com/devg-dli/zh-cn_image_0000001200327862.png "点击放大")
表2开发流程说明 
| 序号 | 阶段                | 操作界面          | 说明                                                                                                                         |
|:---|:---|:---|:---|
| 1  | 新建Maven工程，配置pom文件 | IntelliJ IDEA |  参考[操作步骤]说明，编写UDF函数代码。  |
| 2  | 编写UDF函数代码         | IntelliJ IDEA |  参考[操作步骤]说明，编写UDF函数代码。  |
| 3  | 调试，编译代码并导出Jar包    | IntelliJ IDEA |  参考[操作步骤]说明，编写UDF函数代码。  |
| 4  | 上传Jar包到OBS        | OBS控制台        | 将生成的UDF函数Jar包文件上传到OBS目录下。                                                                                                  |
| 5  | 创建DLI的UDF函数       | DLI控制台        | 在DLI控制台的SQL作业管理界面创建使用的UDF函数。                                                                                               |
| 6  | 验证和使用DLI的UDF函数    | DLI控制台        | 在DLI作业中使用创建的UDF函数。                                                                                                         |
   
 #### 操作步骤
1. 新建Maven工程，配置pom文件。以下通过IntelliJ IDEA 2020.2工具操作演示。
   1. 打开IntelliJ IDEA，选择"File \> New \> Project"。
      图2新建Project   
      ![](https://support.huaweicloud.com/devg-dli/zh-cn_image_0000001245448995.png "点击放大") 
   
   2. 选择Maven，Project SDK选择1.8，单击"Next"。
      图3选择Maven   
      ![](https://support.huaweicloud.com/devg-dli/zh-cn_image_0000001245660555.png "点击放大") 
   
   3. 定义样例工程名和配置样例工程存储路径，单击"Finish"完成工程创建。
      图4创建工程   
      ![](https://support.huaweicloud.com/devg-dli/zh-cn_image_0000001245649477.png "点击放大") 
   
   4. 在pom.xml文件中添加如下配置。
      ```
      <dependencies>
              <dependency>
                  <groupId>org.apache.hive</groupId>
                  <artifactId>hive-exec</artifactId>
                  <version>1.2.1</version>
              </dependency>
      </dependencies>
      ```
      图5pom文件中添加配置   
      ![](https://support.huaweicloud.com/devg-dli/zh-cn_image_0000001200329970.png "点击放大") 
   
   5. 在工程路径的"src \> main \> java"文件夹上鼠标右键，选择"New \> Package"，新建Package和类文件。
      图6新建Package和类文件   
      ![](https://support.huaweicloud.com/devg-dli/zh-cn_image_0000001245651049.png "点击放大")
      Package根据需要定义，本示例定义为："com.huawei.demo"，完成后回车。
      图7自定义Package   
      ![](https://support.huaweicloud.com/devg-dli/zh-cn_image_0000001819022101.png "点击放大")
      在包路径下新建Java Class文件，本示例定义为：SumUdfDemo。
      图8新建Java Class文件   
      ![](https://support.huaweicloud.com/devg-dli/zh-cn_image_0000001818862149.png "点击放大") 
    
2. 编写UDF函数代码。UDF函数实现，主要注意以下几点：
   1. 自定义UDF需要继承org.apache.hadoop.hive.ql.exec.UDF。
   
   2. 需要实现evaluate函数，evaluate函数支持重载。
   
   
   详细UDF函数实现，可以参考如下样例代码：
   ```
   package com.huawei.demo;
   import org.apache.hadoop.hive.ql.exec.UDF;
     public class SumUdfDemo extends UDF {
       public int evaluate(int a, int b) {
        return a + b;
     }
    }
   ```
   
3. 编写调试完成代码后，通过IntelliJ IDEA工具编译代码并导出Jar包。
   1. 单击工具右侧的"Maven"，参考下图分别单击"clean"、"compile"对代码进行编译。 编译成功后，单击"package"对代码进行打包。
      图9编译打包   
      ![](https://support.huaweicloud.com/devg-dli/zh-cn_image_0000001245535709.png "点击放大")
      打包成功后，生成的Jar包会放到target目录下，以备后用。本示例将会生成到："D:\\DLITest\\MyUDF\\target"下名为"MyUDF-1.0-SNAPSHOT.jar"。
      图10生成Jar包   
      ![](https://support.huaweicloud.com/devg-dli/zh-cn_image_0000001245456049.png "点击放大") 
    
4. 登录OBS控制台，将生成的Jar包文件上传到OBS路径下。
   ![](https://support.huaweicloud.com/devg-dli/public_sys-resources/note_3.0-zh-cn.png)
   Jar包文件上传的OBS桶所在的区域需与DLI的队列区域相同，不可跨区域执行操作。
   
5. （可选）可以将Jar包文件上传到DLI的程序包管理中，方便后续统一管理。
   1. 登录DLI管理控制台，单击"数据管理 \> 程序包管理"。
   
   2. 在"程序包管理"页面，单击右上角的"创建"创建程序包。
   
   3. 在"创建程序包"对话框，配置以下参数。
      1. 包类型：选择"JAR"。
      
      2. OBS路径：程序包所在的OBS路径。
      
      3. 分组设置和组名称根据情况选择设置，方便后续识别和管理程序包。
       
   
   4. 单击"确定"，完成创建程序包。
    
6. 创建UDF函数。
   1. 登录DLI管理控制台，单击"SQL编辑器"，执行引擎选择"spark"，选择已创建的SQL队列和数据库。
      图11选择队列和数据库   
      ![](https://support.huaweicloud.com/devg-dli/zh-cn_image_0000001255988352.png "点击放大") 
   
   2. 在SQL编辑区域输入下列命令创建UDF函数，单击"执行"提交创建。
      ```
      CREATE FUNCTION TestSumUDF AS 'com.huawei.demo.SumUdfDemo' using jar 'obs://dli-test-obs01/MyUDF-1.0-SNAPSHOT.jar';
      ```
      
    
7. 重启原有SQL队列，使得创建的Function生效。
   1. 登录数据湖探索管理控制台，选择"队列管理"，在对应"SQL队列"类型作业的"操作"列，单击"重启"。
   
   2. 在"重启队列"界面，选择"确定"完成队列重启。
    
8. 使用UDF函数。 在查询语句中使用[6]中创建的UDF函数:
   ```
   select TestSumUDF(1,2);
   ```
   图12执行结果   
   ![](https://support.huaweicloud.com/devg-dli/zh-cn_image_0000001200820412.png "点击放大") 
9. （可选）删除UDF函数。 如果不再使用UDF函数，可执行以下语句删除该函数:
   ```
   Drop FUNCTION TestSumUDF;
   ```
   
 
