文章目錄
一 下載源碼
首先進入網站:http://archive.cloudera.com/cdh5/cdh/5/
然後搜索hive-1.1.0-cdh5.15.1-src
二 自定義函數
2.1 添加隨機數前綴函數
解壓之後,可以用idea打開工程,然後在目錄hive-1.1.0-cdh5.15.1/ql/src/java/org/apache/hadoop/hive/ql/udf下新建一個類UDFAddRandomPrefix
//這裏的描述是我們在終端可以使用命令查看該函數的使用幫助
@Description(name = "add_random_prefix",
value = "_FUNC_(input,upperLimit) - Returns added prefix string," +
" which the random upper limit is 1 to upperLimit",
extended = "Example:\n"
+ " > SELECT _FUNC_('hive',5) FROM src LIMIT 1;\n"
+ " 3_hive\n"
+ " > SELECT _FUNC_('hive',5) FROM src LIMIT 1;\n"
+ " 1_hive\n")
public class UDFAddRandomPrefix extends UDF {
//函數的方法
public String evaluate(String input,Integer upperLimit) {
Random random = new Random();
int i = random.nextInt(upperLimit) + 1;
return i + "_" + input;
}
//用於本地測試上面的方法
public static void main(String[] args) {
UDFAddRandomPrefix UDFAddRandomPrefix = new UDFAddRandomPrefix();
String android = UDFAddRandomPrefix.evaluate("android",10);
System.out.println(android);
}
}
2.2 移除前綴函數
同樣的在目錄hive-1.1.0-cdh5.15.1/ql/src/java/org/apache/hadoop/hive/ql/udf下新建一個類UDFRemoveRandomPrefix
//說明文檔
@Description(name = "remove_random_prefix",
value = "_FUNC_(input) - Returns removed prefix string,",
extended = "Example:\n"
+ " > SELECT _FUNC_('3_hive') FROM src LIMIT 1;\n"
+ " hive\n"
+ " > SELECT _FUNC_('5_hive') FROM src LIMIT 1;\n"
+ " hive\n")
public class UDFRemoveRandomPrefix extends UDF {
//函數的方法
public String evaluate(String input) {
String[] split = input.split("_");
return split[1];
}
//用於本地測試
public static void main(String[] args) {
UDFRemoveRandomPrefix UDFRemoveRandomPrefix = new UDFRemoveRandomPrefix();
String evaluate = UDFRemoveRandomPrefix.evaluate("80_android");
System.out.println(evaluate);
}
}
2.3 註冊函數
上面的函數類我們已經定義好了,但是要註冊一下,hive纔會知道我們自己寫的兩個函數,
在類FunctionRegistry
的靜態代碼塊static
下添加如下代碼:
system.registerUDF("remove_random_prefix",UDFRemoveRandomPrefix.class,false);
system.registerUDF("add_random_prefix", UDFAddRandomPrefix.class,false);
三 編譯
終端切換到hive-1.1.0-cdh5.15.1
目錄
然後執行下面命令
mvn clean package -DskipTests -Phadoop-2 -Pdist
最後出現下面這個圖,說明編譯成功
四 結果
最終打包後的文件在hive-1.1.0-cdh5.15.1/packaging/target
目錄下
後面直接進行部署就可以了,可以看我的這個文章:hive部署
下圖是hive-exec模塊的編譯結果
因爲我們剛剛添加的函數在hive-exec模塊下添加自定義函數的,也可以把hive-exec-1.1.0-cdh5.15.1.jar直接上傳部署好hive的lib目錄下面
五 測試函數
查看函數
show functions;
可以看到我們自己定義的兩個函數了,如下圖
我們看下函數的詳細描述,看看文檔是不是我們剛剛寫的
desc function extended add_random_prefix;
如下圖,這些不就是我們剛剛自定義函數寫的說明麼
我們來使用一下這個函數:
select add_random_prefix('hive',10);
自動給我們加上隨機數了
我們再測試一下移除隨機數
select remove_random_prefix('9_hive');
到這裏,說明我們的自定義的函數沒有問題
六 解決數據傾斜問題
數據傾斜一般發生在聚合計算的時候,由於相同的key過多導致的,導致有一個task可能會計算的很慢,導致整個job的時間很長
uid | pid |
---|---|
user1 | product1 |
user2 | product3 |
user3 | product1 |
user3 | product1 |
user3 | product1 |
user3 | product1 |
user3 | product2 |
user3 | product3 |
user3 | product11 |
user3 | product12 |
user3 | product11 |
user3 | product1 |
user3 | product2 |
user3 | product13 |
user3 | product1 |
user3 | product1 |
user3 | product1 |
user3 | product1 |
1.上面這個數據,是每個用戶購買的產品,現在我們要計算每個用戶總共購買了多少產品;
2.從上面的數據可以看出user3用戶比較多,如果數量再擴大幾十萬倍,進行聚合的時候會發生數據傾斜的問題了,那麼我們可以用上面兩個自定義的函數解決數據傾斜問題
6.1 先把uid打散
打散的意思就是在uid字段的值前面加上隨機數
select add_random_prefix(uid,5) as rdm_uid from user_pid;
6.2 第一次聚合
把上面一次查詢的結果作爲臨時表,對打散後的uid進行第一次聚合
select rdm_uid, count(1) as cnt from
(select add_random_prefix(uid,5) as rdm_uid from user_pid) a
group by rdm_uid;
6.3 移除隨機數
現在可以用移除隨機數的函數,把上面的結果uid前面的隨機數進行移除
select remove_random_prefix(rdm_uid) as uid, cnt from
(select rdm_uid, count(1) as cnt from
(select add_random_prefix(uid,5) as rdm_uid from user_pid) a
group by rdm_uid) b;
6.4 第二次聚合
把上面的結果作爲臨時表,把uid作爲分組條件,對cnt進行求和,就可以得到我們的結果
select uid, sum(cnt) as total_cnt from
(select remove_random_prefix(rdm_uid) as uid, cnt from
(select rdm_uid, count(1) as cnt from
(select add_random_prefix(uid,5) as rdm_uid from user_pid) a
group by rdm_uid) b) c
group by uid;
到此數據傾斜解決