hive自定義函數後,編譯源碼,並解決數據傾斜

一 下載源碼

首先進入網站: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;

在這裏插入圖片描述
到此數據傾斜解決

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章