
# 创建函数
#### 功能描述
平台支持创建使用UDF和UDTF等自定义函数应用于Spark作业开发中。
#### 语法格式
```
CREATE FUNCTION [db_name.]function_name AS class_name
  [USING resource,...]
resource: 
  : JAR file_uri
```
或
```
CREATE OR REPLACE FUNCTION [db_name.]function_name AS class_name
  [USING resource,...]
resource: 
  : JAR file_uri
```
#### 注意事项
- 如果在数据库中存在同名的函数，系统将会报错。
- 只支持Hive语法创建函数。
- 请注意避免该场景：如果创建的自定义函数F1指定类C1，程序包名JAR1，创建自定义函数F2也指定类C1，程序包JAR2，因为F2和F1使用相同的类名，导致功能相互冲突，影响作业执行。
- UDF热加载功能处于受限使用阶段，如需使用请提交工单申请开通。
 
#### 关键字
- USING ：需要加载的资源。可以是JAR、文件或者URI的列表。
- OR REPLACE：支持自定义函数热加载功能。
  - 如果创建自定义函数时**不携带OR REPLACE** ，则需要注意以下场景：
    表1不携带OR REPLACE场景说明 
    | 场景说明                                              | 场景举例                                                                                                                                                           | 生效机制                          | 操作影响                                                   |
    |:---|:---|:---|:---|
    | 场景一：修改了原有程序包类的实现逻辑，重新创建的函数指定的JAR包名和类名保持和原有一致。     | 在**Spark SQL端点**下已创建自定义函数F1，指定类名C1，Jar包名J1。后续对J1包中函数实现做了逻辑修改，重新执行创建函数F2，指定类名C1，Jar包名J1。注意，如果步骤2继续使用函数名F1，则会因为函数名重复导致创建失败。这时可以考虑使用OR REPLACE，或者替换所有作业中的函数F1为F2。 | 需要重启Spark SQL队列后新创建的自定义函数F2生效 | 需要重启Spark SQL队列，影响当前运行的作业。重启队列后，影响F1原有功能，F1的功能变为和F2一样。 |
    | 场景二：在原有程序包类的基础上新增了类，新创建的函数指定为新增的类，包名不变。           | 在Spark SQL队列下已创建自定义函数F1，指定类名C1，Jar包名J1。J1的Jar包中新增了类C2，C1保持不变，新创建自定义函数F2，指定类名C2，Jar包名J1。                                                                        | 需要重启Spark SQL队列后新创建的自定义函数F2生效 | 需要重启Spark SQL队列，影响当前运行的作业。重启队列后，F1的功能不变。               |
    | 场景三：原有程序包类的实现逻辑不变，重新打包程序包名。新创建的函数指定新JAR包名，类名保持不变。 | 在Spark SQL队列下已创建自定义函数F1，指定类名C1，Jar包名J1。重新打包Jar包为J2，功能逻辑不变。新创建的自定义函数F2，指定类名C1，Jar包名J2。                                                                          | 新创建的自定义函数F2立即生效               | 无影响。                                                   |
       
    
  
  - 如果创建自定义函数**携带** **OR** **REPLACE** ，表示需要对已有的函数内容进行功能替换并实时生效。
    该功能处于受限使用阶段，如需使用请提交工单申请开通。
    - 如果要在所有Spark SQL端点上立即生效，需要分别选择Spark SQL端点执行一遍：**CREATE** **OR** REPLACE xxx **FUNCTION** ...，否则没有执行的队列可能延迟0-12小时生效。
    
    - 如果当前运行的作业中使用自定义函数F1，该F1函数指定类名C1，程序包名J1，作业运行了一半后，重新修改J1程序包逻辑，CREATE OR REPLACE FUNCTION F1后，后续作业使用新的F1函数逻辑，但是已执行完一半的作业使用旧的函数逻辑。
      表2携带OR REPLACE场景说明 
      | 场景说明                                              | 场景举例                                                                                                                  | 生效机制                                                                   | 操作影响                               |
      |:---|:---|:---|:---|
      | 场景一：修改了原有程序包类的实现逻辑，重新创建的函数指定的JAR包名和类名保持和原有一致。     | 在Spark SQL队列下已创建自定义函数F1，指定类名C1，Jar包名J1。后续对J1包中函数实现做了逻辑修改，重新执行创建函数F1，指定类名C1，Jar包名J1。                                   | 立即生效                                                                   | F1的功能变成新修改的逻辑。                     |
      | 场景二：在原有程序包类的基础上新增了类，新创建的函数指定为新增的类，包名不变。           | 在Spark SQL队列下已创建自定义函数F1，指定类名C1，Jar包名J1。J1的Jar包中新增了类C2，C1保持不变，新创建自定义函数F2，指定类名C2，Jar包名J1。因为是第一次创建指定C2的函数，这时该F2函数不能立即生效。 | 两种生效方式：1. CREATE OR REPLACE FUNCTION F2创建语句再执行一次生效；2. 重启Spark SQL队列后生效 | 如果是选择重启Spark SQL队列，则会导致当前运行的作业受影响。 |
      | 场景三：修改了原有程序包类的类名，新创建的函数指定为新类名，包名不变。               | 在Spark SQL队列下已创建自定义函数F1，指定类名C1，Jar包名J1。J1的Jar包中修改原C1为C2，C1已经不存在，新创建自定义函数F2，指定类名C2，Jar包名J1。                            | 立即生效                                                                   | F1功能失效，F2功能立即生效。                   |
      | 场景四：原有程序包类的实现逻辑不变，重新打包程序包名。新创建的函数指定新JAR包名，类名保持不变。 | 在Spark SQL队列下已创建自定义函数F1，指定类名C1，Jar包名J1。重新打包Jar包为J2，功能逻辑不变。新创建的自定义函数F2，指定类名C1，Jar包名J2。                                 | 立即生效                                                                   | 无影响。                               |
         
      
      
   
 
#### 示例
创建函数mergeBill。
```
CREATE FUNCTION mergeBill AS 'com.xxx.hiveudf.MergeBill'
  using jar 'obs://onlyci-7/udf/MergeBill.jar';
```
