UDF
-
User-Defined-Function 自定義函數 、一進一出;
-
背景
- 系統內置函數無法解決實際的業務問題,需要開發者自己編寫函數實現自身的業務實現訴求。
- 應用場景非常多,面臨的業務不同導致個性化實現很多,故udf很需要。
-
意義
- 函數擴展得到解決,極大豐富了可定制化的業務需求。
- IO要求-要解決的問題
- in:out=1:1,只能輸入一條記錄當中的數據,同時返回一條處理結果。
- 屬於最常見的自定義函數,像cos,sin,substring,indexof等均是如此要求
-
實現步驟(Java創建自定義UDF類)
- 自定義一個java類
- 繼承UDF類
- 重寫evaluate方法
- 打包類所在項目成一個all-in-one的jar包並上傳到hive所在機器
- 在hive中執行add jar操作,將jar加載到classpath中。
- 在hive中創建模板函數,使得后邊可以使用該函數名稱調用實際的udf函數
- hive sql中像調用系統函數一樣使用udf函數
-
代碼實現
- 功能要求:實現當輸入字符串超過2個字符的時候,多余的字符以”…”來表示。
- 如“12”則返回“12”,如“123”返回“12…”
- 自定義類、繼承UDF、重寫evaluate方法已在代碼中體現
import org.apache.hadoop.hive.ql.exec.UDF; /* * 功能:實現當輸入字符串超過2個字符的時候,多余的字符以"..."來表示。 * 輸入/輸出:* 如“12”則返回“12”,如“123”返回“12..." */ public class ValueMaskUDF extends UDF{ public String evaluate(String input,int maxSaveStringLength,String replaceSign) { if(input.length()<=maxSaveStringLength){ return input; } return input.substring(0,maxSaveStringLength)+replaceSign; } public static void main(String[] args) { System.out.println(new ValueMaskUDF().evaluate("河北省",2,"..."));; } }
UDAF
-
自定義udaf函數self_count,實現系統udaf count的功能
-
Input/Output要求-要解決的問題
- in:out=n:1,即接受輸入N條記錄當中的數據,同時返回一條處理結果。
- 屬於最常見的自定義函數,像count,sum,avg,max等均是如此要求
-
實現步驟
- 自定義一個java類
- 繼承UDAF類
- 內部定義一個靜態類,實現UDAFEvaluator接口
- 實現方法init,iterate,terminatePartial,merge,terminate,共5個方法. 詳見下圖
- 在hive中執行add jar操作,將jar加載到classpath中。
- 在hive中創建模板函數,使得后邊可以使用該函數名稱調用實際的udf函數
-
hive sql中像調用系統函數一樣使用udaf函數
Hive_UDAF五個方法.png
-
業務測試
輸入:

輸入.png
輸出:

輸出.png
- UDAF代碼開發
import java.util.HashMap; import java.util.Map; import java.util.Set; import org.apache.hadoop.hive.ql.exec.UDAF; import org.apache.hadoop.hive.ql.exec.UDAFEvaluator; import org.apache.log4j.Logger; /** * 實現多條數據合並成一條數據 */ // 主類繼承UDAF public class StudentScoreAggUDAF extends UDAF { // 日志對象初始化 public static Logger logger = Logger.getLogger(StudentScoreAggUDAF.class); // 靜態類實現UDAFEvaluator public static class Evaluator implements UDAFEvaluator { // 設置成員變量,存儲每個統計范圍內的總記錄數 private Map<String, String> courseScoreMap; //初始化函數,map和reduce均會執行該函數,起到初始化所需要的變量的作用 public Evaluator() { init(); } // 初始化函數間傳遞的中間變量 public void init() { courseScoreMap = new HashMap<String, String>(); } //map階段,返回值為boolean類型,當為true則程序繼續執行,當為false則程序退出 public boolean iterate(String course, String score) { if (course == null || score == null) { return true; } courseScoreMap.put(course, score); return true; } /** * 類似於combiner,在map范圍內做部分聚合,將結果傳給merge函數中的形參mapOutput * 如果需要聚合,則對iterator返回的結果處理,否則直接返回iterator的結果即可 */ public Map<String, String> terminatePartial() { return courseScoreMap; } // reduce 階段,用於逐個迭代處理map當中每個不同key對應的 terminatePartial的結果 public boolean merge(Map<String, String> mapOutput) { this.courseScoreMap.putAll(mapOutput); return true; } // 處理merge計算完成后的結果,即對merge完成后的結果做最后的業務處理 public String terminate() { return courseScoreMap.toString(); } } }
測試sql語句
select id,username,score_agg(course,score) from student_score group by id,username;
- 自定義udaf實現max:https://www.cnblogs.com/itxuexiwang/p/6263110.html
UDTF
- User-Defined Table-Generating Functions
- 要解決一行輸入多行輸出的問題,問題的應用場景不少
- 用udtf解決一行輸入多行輸出的不多,往往被lateral view explode+udf等替代實現,比直接用udtf會更簡單、直接一些