使用Hive中自定義UDAF函式實現統計區域產品使用者訪問排名

loveheping發表於2018-01-26
UDAF實現方法: 
1,使用者的UDAF必須繼承了org.apache.hadoop.hive.ql.exec.UDAF;
2,使用者的UDAF必須包含至少一個實現了org.apache.hadoop.hive.ql.exec的靜態類,諸如實現了 UDAFEvaluator 
3,一個計算函式必須實現的5個方法的具體含義如下:
init():主要是負責初始化計算函式並且重設其內部狀態,一般就是重設其內部欄位。一般在靜態類中定義一個內部欄位來存放最終的結果。
iterate():每一次對一個新值進行聚集計算時候都會呼叫該方法,計算函式會根據聚集計算結果更新內部狀態。當輸 入值合法或者正確計算了,則       就返回true。
terminatePartial():Hive需要部分聚集結果的時候會呼叫該方法,必須要返回一個封裝了聚集計算當前狀態的物件。
merge():Hive進行合併一個部分聚集和另一個部分聚集的時候會呼叫該方法。
terminate():Hive最終聚集結果的時候就會呼叫該方法。計算函式需要把狀態作為一個值返回給使用者。

mapreduce階段呼叫函式 
MAP 

init() 
iterate() 
terminatePartial()

Combiner 

merge() 
terminatePartial()

REDUCE 

init() 
merge() 
terminate()

一、自定義UDAF函式

點選(此處)摺疊或開啟
  1. package hive.org.ruozedata;

  2. import java.util.*;

  3. import org.apache.hadoop.hive.ql.exec.UDAF;
  4. import org.apache.hadoop.hive.ql.exec.UDAFEvaluator;
  5. import org.apache.log4j.Logger;

  6.     public class UserClickUDAF extends UDAF {

  7.     // 日誌物件初始化
  8.     public static Logger logger = Logger.getLogger(UserClickUDAF.class);

  9.     // 靜態類實現UDAFEvaluator
  10.     public static class Evaluator implements UDAFEvaluator {
  11.         // 設定成員變數,儲存每個統計範圍內的總記錄數
  12.         private static Map<String, String> courseScoreMap;

  13.         private static Map<String, String> city_info;
  14.         private static Map<String, String> product_info;
  15.         private static Map<String, String> user_click;

  16.         //初始化函式,map和reduce均會執行該函式,起到初始化所需要的變數的作用
  17.         public Evaluator() {
  18.             init();
  19.         }

  20.         // 初始化函式間傳遞的中間變數
  21.         public void init() {
  22.             courseScoreMap = new HashMap<String, String>();
  23.             city_info = new HashMap<String, String>();
  24.             product_info = new HashMap<String, String>();
  25.        }

  26.         //map階段,返回值為boolean型別,當為true則程式繼續執行,當為false則程式退出
  27.         public boolean iterate(String pcid, String pcname, String pccount) {
  28.             if (pcid == null || pcname == null || pccount == null) {
  29.                 return true;
  30.             }

  31.             if (pccount.equals("-1")) {
  32.                 // 城市表
  33.                 city_info.put(pcid, pcname);
  34.             }
  35.             else if (pccount.equals("-2")) {
  36.                 // 產品表
  37.                 product_info.put(pcid, pcname);
  38.             }
  39.             else
  40.             {
  41.                 // 處理使用者點選關聯
  42.                 unionCity_Prod_UserClic1(pcid, pcname, pccount);
  43.            }
  44.             return true;
  45.         }

  46.         // 處理使用者點選關聯
  47.         private void unionCity_Prod_UserClic1(String pcid, String pcname, String pccount) {
  48.             if (product_info.containsKey(pcid)) {
  49.                 if (city_info.containsKey(pcname)) {
  50.                     String city_name = city_info.get(pcname);
  51.                     String prod_name = product_info.get(pcid);
  52.                     String cp_name = city_name + prod_name;

  53.                     // 如果之前已經Put過Key值為區域資訊,則把記錄相加處理
  54.                     if (courseScoreMap.containsKey(cp_name)) {
  55.                         int pcrn = 0;
  56.                         String strTemp = courseScoreMap.get(cp_name);
  57.                         String courseScoreMap_pn = strTemp.substring(strTemp.lastIndexOf("\t".toString())).trim();
  58.                         pcrn = Integer.parseInt(pccount) + Integer.parseInt(courseScoreMap_pn);

  59.                         courseScoreMap.put(cp_name, city_name + "\t" + prod_name + "\t" + Integer.toString(pcrn));
  60.                     }
  61.                     else {
  62.                         courseScoreMap.put(cp_name, city_name + "\t" + prod_name + "\t" + pccount);
  63.                     }
  64.                 }
  65.             }
  66.         }

  67.         /**
  68.          * 類似於combiner,在map範圍內做部分聚合,將結果傳給merge函式中的形參mapOutput
  69.          * 如果需要聚合,則對iterator返回的結果處理,否則直接返回iterator的結果即可
  70.          */
  71.         public Map<String, String> terminatePartial() {
  72.             return courseScoreMap;
  73.         }

  74.         // reduce 階段,用於逐個迭代處理map當中每個不同key對應的 terminatePartial的結果
  75.         public boolean merge(Map<String, String> mapOutput) {
  76.             this.courseScoreMap.putAll(mapOutput);
  77.             return true;
  78.         }
  79.         // 處理merge計算完成後的結果,即對merge完成後的結果做最後的業務處理
  80.         public String terminate() {
  81.             return courseScoreMap.toString();
  82.         }
  83.     }
  84. }
二、使用新增Jar包與Hive中臨時函式
點選(此處)摺疊或開啟
  1. DROP TEMPORARY FUNCTION user_click;

  2. add jar /data/hive_udf-1.0.jar;

  3. CREATE TEMPORARY FUNCTION user_click AS 'hive.org.ruozedata.UserClickUDAF';
三、呼叫自定義UDAF函式處理資料

點選(此處)摺疊或開啟

  1. insert overwrite directory '/works/tmp1' ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t'
  2. select regexp_replace(substring(rs, instr(rs, '=')+1), '}', '') from (
  3.   select explode(split(user_click(pcid, pcname, type),',')) as rs from (
  4.     select * from (
  5.       select '-2' as type, product_id as pcid, product_name as pcname from product_info
  6.       union all
  7.       select '-1' as type, city_id as pcid,area as pcname from city_info
  8.       union all
  9.       select count(1) as type,
  10.              product_id as pcid,
  11.              city_id as pcname
  12.         from user_click
  13.        where action_time='2016-05-05'
  14.       group by product_id,city_id
  15.     ) a
  16.   order by type) b
  17. ) c
四、建立Hive臨時外部表

點選(此處)摺疊或開啟

  1. create external table tmp1(
  2. city_name string,
  3. product_name string,
  4. rn string
  5. )
  6. ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t'
  7. location '/works/tmp1';
五、-統計最終區域前3產品排名

點選(此處)摺疊或開啟

  1. select * from (
  2. select city_name,
  3.        product_name,
  4.        floor(sum(rn)) visit_num,
  5.        row_number()over(partition by city_name order by sum(rn) desc) rn,
  6.        '2016-05-05' action_time
  7.   from tmp1
  8.  group by city_name,product_name
  9. ) a where rn <=3
六、統計結果


此方法可能不會很好,但最少可以起到一定的拋磚引玉的功效。希望大家不吝賜教!



若澤大資料交流群:671914634


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31511218/viewspace-2150561/,如需轉載,請註明出處,否則將追究法律責任。

相關文章