hive自定義UDTF函數(shù)算芯,步驟講解

目錄:
一柒昏、繼承GenericUDTF抽象類
二、重寫方法initialize()
三熙揍、實現(xiàn)抽象方法process()
四职祷、實現(xiàn)抽象方法close()
五、自定義將一行字符串轉(zhuǎn)多行代碼

UDTF(User-Defined Table-Generating Functions)是一進多出函數(shù)届囚,如hive中的explode()函數(shù)有梆。
在學習自定義UDTF函數(shù)時,一定要知道hive中的UDTF函數(shù)如何使用意系,不會的先看這篇文章:hive中UDTF函數(shù)explode詳解 + explode與lateral view 3套案例練習泥耀。

自定義UDF函數(shù)步驟如下:

自定義函數(shù)、實現(xiàn)UDTF一進多出功能昔字,我們主要關心的是要繼承什么類爆袍,實現(xiàn)什么方法首繁。
1)繼承org.apache.hadoop.hive.ql.udf.generic.GenericUDTF
2)重寫initialize、process陨囊、close方法

備注:我們在繼承這個類的時候弦疮,只需要關心它能實現(xiàn)什么功能、我們需要處理什么業(yè)務邏輯蜘醋。就像在使用sql函數(shù)也是這樣胁塞,我以前還糾結為什么它可以實現(xiàn)這樣的功能。
不過繼承的這個類可以實現(xiàn)什么功能压语,怎么使用一定一定要清楚啸罢、熟練掌握。

一胎食、繼承GenericUDTF抽象類

繼承GenericUDTF抽象類時扰才,我們需要重寫initialize方法、并實現(xiàn)2個抽象方法(process厕怜、close).
在Alt + Enter回車時衩匣,只提示我們實現(xiàn)兩個方法抽象方法process、close粥航。initialize方法不是抽象方法不用實現(xiàn)琅捏,但是該方法需要重寫,不然會報錯递雀。

    1. initialize初始化:UDTF首先會調(diào)用initialize方法柄延,此方法返回UDTF的返回行的信息(返回個數(shù),類型缀程,名稱)搜吧。initialize針對任務調(diào)一次
    1. process:初始化完成后,會調(diào)用process方法杠输,對傳入的參數(shù)進行處理赎败,可以通過forword()方法把結果寫出。
      process傳入一行數(shù)據(jù)寫出去多次蠢甲,與mapreduce中的map方法很像僵刮,也是一行一行的數(shù)據(jù)傳入,傳入一行數(shù)據(jù)輸出多行數(shù)據(jù)鹦牛,如:mapreduce單詞計數(shù)搞糕。process針對每行數(shù)據(jù)調(diào)用一次該方法
    1. close:最后close()方法調(diào)用,對需要清理的方法進行清理曼追,close()方法針對整個任務調(diào)一次
public abstract class GenericUDTF {
…
…
    /** @deprecated */
    @Deprecated
    public StructObjectInspector initialize(ObjectInspector[] argOIs) throws UDFArgumentException {
        throw new IllegalStateException("Should not be called directly");
    }

    public abstract void process(Object[] var1) throws HiveException;

    public abstract void close() throws HiveException;
…
…
}

二窍仰、重寫方法initialize()

initialize方法是針對整個任務調(diào)一次,initialize作用是定義輸出字段的列名礼殊、和輸出字段的數(shù)據(jù)類型驹吮,重寫該方法時里面有一些知識點需要我們記

    1. 在定義輸出字段(fieldNames)數(shù)據(jù)類型(ieldOIs)時针史,該處定義的數(shù)據(jù)類型跟常用的Java數(shù)據(jù)類型不一致,需要格外去記碟狞。
      比如string數(shù)據(jù)類型這里用的是javaStringObjectInspector;int 數(shù)據(jù)類型這里用的是javaIntObjectInspector
    1. 輸出的字段名是一個集合啄枕,而不是一個字段。也就是炸裂這個方法可以輸出多個列族沃。如:hive中explode對數(shù)組炸裂時返回一個字段,explode對map數(shù)據(jù)炸裂時返回2個字段.
    1. 輸出的列數(shù)據(jù)類型也是一個集合频祝。
    1. 返回列字段名和列數(shù)據(jù)類型時,是返回的是一個工廠數(shù)據(jù)類型ObjectInspectorFactory.getStandardStructObjectInspector(fieldNames, fieldOIs)脆淹,記住就好了常空。
      這里語言描述有問題,底層的還沒理解到盖溺,就是定義好輸出的字段和字段數(shù)據(jù)類型漓糙,然后把這兩個參數(shù)塞到getStandardStructObjectInspector方法里面去。
 @Override
    /**
     * 返回數(shù)據(jù)類型:StructObjectInspector
     * 定義輸出數(shù)據(jù)的列名咐柜、和數(shù)據(jù)類型兼蜈。
     */
    public StructObjectInspector initialize(StructObjectInspector argOIs) throws UDFArgumentException {
        //fieldNames字段名,函數(shù)定義字段名拙友,關心輸入和輸出。應該為輸出的字段名

        List<String> fieldNames = new ArrayList<String>();//問題歼郭?為什么函數(shù)輸出的字段名是一個集合遗契,而不是一個字段?
        //也就是炸裂這個方法可以輸出多個列病曾,我們使用hive默認的explode函數(shù)炸裂的時候是炸裂一個列牍蜂,
        //但是UDTF炸裂可以有多個列
        fieldNames.add("world");

        List<ObjectInspector> fieldOIs = new ArrayList<ObjectInspector>(); //類型,列輸出類型
        fieldOIs.add(PrimitiveObjectInspectorFactory.javaStringObjectInspector);

        return ObjectInspectorFactory.getStandardStructObjectInspector(fieldNames, fieldOIs);
    }

三、實現(xiàn)抽象方法process()

process方法是一行數(shù)據(jù)調(diào)用一次process方法泰涂,即有多少行數(shù)據(jù)就會調(diào)用多少次process方法鲫竞。主要作用是對傳入的每一行數(shù)據(jù)寫出去多次,調(diào)用forward()將數(shù)據(jù)寫入到一個緩沖區(qū)。

有2個點需要記妆泼伞:

  • 1)在initialize初始化的時候从绘,定義輸出字段的數(shù)據(jù)類型是集合,我們調(diào)用forward()將數(shù)據(jù)寫入到一個緩沖區(qū)是牢,寫入緩沖區(qū)的數(shù)據(jù)也要是集合僵井。
  • 2)如果只定義了一個集合,每次調(diào)用forward()寫數(shù)據(jù)之前驳棱,需要將集合中的數(shù)據(jù)給清空批什。


    //數(shù)據(jù)的集合
    private List<String> dataList = new ArrayList<String>();

 /**
     * process(Object[] objects) 參數(shù)是一個數(shù)組,但是hive中的explode函數(shù)接受的是一個社搅,一進多出
     * @param args
     * @throws HiveException
     */
    public void process(Object[] args) throws HiveException {
        //我們現(xiàn)在的需求是傳入一個數(shù)據(jù)驻债,在傳入一個分割符

        //1.獲取數(shù)據(jù)
        String data = args[0].toString();

        //2.獲取分割符
        String splitKey = args[1].toString();

        //3.切分數(shù)據(jù),得到一個數(shù)組
        String[] words = data.split(splitKey);

        //4.想把words里面的數(shù)據(jù)全部寫出去乳规。類似在map方法中,通過context.write方法
        // 定義是集合合呐、寫出去是一個string暮的,類型不匹配,寫出也要寫出一個集合
        for (String word : words) {
            //5.將數(shù)據(jù)放置集合合砂,EG:傳入"hello,world,hdfs"---->寫出需要寫n次青扔,hello\world
            dataList.clear();//清空數(shù)據(jù)集合

            dataList.add(word);

            //5.寫出數(shù)據(jù)的操作
            forward(dataList);
        }
    }

四、實現(xiàn)抽象方法close()

這里沒有io流的操作所以不需要關閉翩伪。

關于是否有IO流以及是否關閉IO流不清楚微猖。

    public void close() throws HiveException {

    }

五、自定義將一行字符串轉(zhuǎn)多行代碼

package com.atguigu.udtf;

import org.apache.hadoop.hive.ql.exec.UDFArgumentException;
import org.apache.hadoop.hive.ql.metadata.HiveException;
import org.apache.hadoop.hive.ql.udf.generic.GenericUDTF;
import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspectorFactory;
import org.apache.hadoop.hive.serde2.objectinspector.StructObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorFactory;

import java.util.ArrayList;
import java.util.List;

/**
 * 類兩邊有一些陰影是抽象類缘屹,繼承抽象類就要實現(xiàn)抽象方法
 */
public class SplitUDTF extends GenericUDTF {
    //數(shù)據(jù)的集合
    private List<String> dataList = new ArrayList<String>();

    @Override
    /**
     * 返回數(shù)據(jù)類型:StructObjectInspector
     * 定義輸出數(shù)據(jù)的列名凛剥、和數(shù)據(jù)類型。
     */
    public StructObjectInspector initialize(StructObjectInspector argOIs) throws UDFArgumentException {
        //fieldNames字段名轻姿,函數(shù)定義字段名犁珠,關心輸入和輸出。應該為輸出的字段名

        List<String> fieldNames = new ArrayList<String>();//問題互亮?為什么函數(shù)輸出的字段名是一個集合犁享,而不是一個字段?
        //也就是炸裂這個方法可以輸出多個列豹休,我們使用hive默認的explode函數(shù)炸裂的時候是炸裂一個列炊昆,
        //但是UDTF炸裂可以有多個列
        fieldNames.add("world");

        List<ObjectInspector> fieldOIs = new ArrayList<ObjectInspector>(); //類型,列輸出類型
        fieldOIs.add(PrimitiveObjectInspectorFactory.javaStringObjectInspector);
//        fieldOIs.add(PrimitiveObjectInspectorFactory.javaIntObjectInspector);

        return ObjectInspectorFactory.getStandardStructObjectInspector(fieldNames, fieldOIs);
    }

    /**
     * process(Object[] objects) 參數(shù)是一個數(shù)組,但是hive中的explode函數(shù)接受的是一個威根,一進多出
     * @param args
     * @throws HiveException
     */
    public void process(Object[] args) throws HiveException {
        //我們現(xiàn)在的需求是傳入一個數(shù)據(jù)凤巨,在傳入一個分割符

        //1.獲取數(shù)據(jù)
        String data = args[0].toString();

        //2.獲取分割符
        String splitKey = args[1].toString();

        //3.切分數(shù)據(jù),得到一個數(shù)組
        String[] words = data.split(splitKey);

        //4.想把words里面的數(shù)據(jù)全部寫出去。類似在map方法中洛搀,通過context.write方法
        // 定義是集合敢茁、寫出去是一個string,類型不匹配留美,寫出也要寫出一個集合
        for (String word : words) {
            //5.將數(shù)據(jù)放置集合彰檬,EG:傳入"hello,world,hdfs"---->寫出需要寫n次,hello\world
            dataList.clear();//清空數(shù)據(jù)集合

            dataList.add(word);

            //5.寫出數(shù)據(jù)的操作
            forward(dataList);
        }
    }

    public void close() throws HiveException {

    }
}

后記

最后文章里面独榴,還有很多描述不清楚的地方僧叉,以及我不明白的地方,大家也可以去看看其他的文章棺榔。

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末瓶堕,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子症歇,更是在濱河造成了極大的恐慌郎笆,老刑警劉巖谭梗,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異宛蚓,居然都是意外死亡激捏,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進店門凄吏,熙熙樓的掌柜王于貴愁眉苦臉地迎上來远舅,“玉大人,你說我怎么就攤上這事痕钢⊥及兀” “怎么了?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵任连,是天一觀的道長蚤吹。 經(jīng)常有香客問我,道長随抠,這世上最難降的妖魔是什么裁着? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮拱她,結果婚禮上二驰,老公的妹妹穿的比我還像新娘。我一直安慰自己秉沼,他們只是感情好诸蚕,可當我...
    茶點故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著氧猬,像睡著了一般。 火紅的嫁衣襯著肌膚如雪坏瘩。 梳的紋絲不亂的頭發(fā)上盅抚,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天,我揣著相機與錄音倔矾,去河邊找鬼妄均。 笑死,一個胖子當著我的面吹牛哪自,可吹牛的內(nèi)容都是我干的丰包。 我是一名探鬼主播,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼壤巷,長吁一口氣:“原來是場噩夢啊……” “哼邑彪!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起胧华,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤寄症,失蹤者是張志新(化名)和其女友劉穎宙彪,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體有巧,經(jīng)...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡释漆,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了篮迎。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片男图。...
    茶點故事閱讀 38,018評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖甜橱,靈堂內(nèi)的尸體忽然破棺而出逊笆,到底是詐尸還是另有隱情,我是刑警寧澤渗鬼,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布览露,位于F島的核電站,受9級特大地震影響譬胎,放射性物質(zhì)發(fā)生泄漏差牛。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一堰乔、第九天 我趴在偏房一處隱蔽的房頂上張望偏化。 院中可真熱鬧,春花似錦镐侯、人聲如沸侦讨。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽韵卤。三九已至,卻和暖如春崇猫,著一層夾襖步出監(jiān)牢的瞬間沈条,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工诅炉, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留蜡歹,地道東北人。 一個月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓涕烧,卻偏偏與公主長得像月而,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子议纯,可洞房花燭夜當晚...
    茶點故事閱讀 42,762評論 2 345