Hive- UDF&GenericUDF

hive udf簡介

在Hive中,用戶可以自定義一些函數(shù)惕稻,用于擴展HiveQL的功能,而這類函數(shù)叫做UDF(用戶自定義函數(shù))。UDF分為兩大類:UDAF(用戶自定義聚合函數(shù))和UDTF(用戶自定義表生成函數(shù))疾瓮。在介紹UDAF和UDTF實現(xiàn)之前,我們先在本章介紹簡單點的UDF實現(xiàn)——UDF和GenericUDF飒箭,然后以此為基礎在下一章介紹UDAF和UDTF的實現(xiàn)狼电。

Hive有兩個不同的接口編寫UDF程序蜒灰。一個是基礎的UDF接口,一個是復雜的GenericUDF接口肩碟。

org.apache.hadoop.hive.ql. exec.UDF 基礎UDF的函數(shù)讀取和返回基本類型强窖,即Hadoop和Hive的基本類型。如削祈,Text翅溺、IntWritable、LongWritable髓抑、DoubleWritable等咙崎。

org.apache.hadoop.hive.ql.udf.generic.GenericUDF 復雜的GenericUDF可以處理Map、List吨拍、Set類型褪猛。

注解使用:

@Describtion注解是可選的,用于對函數(shù)進行說明羹饰,其中的FUNC字符串表示函數(shù)名伊滋,當使用DESCRIBE FUNCTION命令時,替換成函數(shù)名队秩。@Describtion包含三個屬性:

  • name:用于指定Hive中的函數(shù)名新啼。
  • value:用于描述函數(shù)的參數(shù)。
  • extended:額外的說明刹碾,如燥撞,給出示例。當使用DESCRIBE FUNCTION EXTENDED name的時候打印迷帜。

而且物舒,Hive要使用UDF,需要把Java文件編譯戏锹、打包成jar文件冠胯,然后將jar文件加入到CLASSPATH中,最后使用CREATE FUNCTION語句定義這個Java類的函數(shù):

  1. hive> ADD jar /root/experiment/hive/hive-0.0.1-SNAPSHOT.jar;
  2. hive> CREATE TEMPORARY FUNCTION hello AS "edu.wzm.hive. HelloUDF";
  3. hive> DROP TEMPORARY FUNCTION IF EXIST hello;

udf

簡單的udf實現(xiàn)很簡單锦针,只需要繼承udf荠察,然后實現(xiàn)evaluate()方法就行了。evaluate()允許重載奈搜。

一個例子:

@Description(  
    name = "hello",  
    value = "_FUNC_(str) - from the input string"  
        + "returns the value that is \"Hello $str\" ",  
    extended = "Example:\n"  
        + " > SELECT _FUNC_(str) FROM src;"  
)  
public class HelloUDF extends UDF{  
      
    public String evaluate(String str){  
        try {  
            return "Hello " + str;  
        } catch (Exception e) {  
            // TODO: handle exception  
            e.printStackTrace();  
            return "ERROR";  
        }  
    }  
}  

genericUDF

GenericUDF實現(xiàn)比較復雜悉盆,需要先繼承GenericUDF。這個API需要操作Object Inspectors馋吗,并且要對接收的參數(shù)類型和數(shù)量進行檢查焕盟。GenericUDF需要實現(xiàn)以下三個方法:

//這個方法只調用一次,并且在evaluate()方法之前調用宏粤。該方法接受的參數(shù)是一個ObjectInspectors數(shù)組脚翘。該方法檢查接受正確的參數(shù)類型和參數(shù)個數(shù)灼卢。  
abstract ObjectInspector initialize(ObjectInspector[] arguments);  
  
//這個方法類似UDF的evaluate()方法。它處理真實的參數(shù)来农,并返回最終結果鞋真。  
abstract Object evaluate(GenericUDF.DeferredObject[] arguments);  
  
//這個方法用于當實現(xiàn)的GenericUDF出錯的時候,打印出提示信息沃于。而提示信息就是你實現(xiàn)該方法最后返回的字符串涩咖。  
abstract String getDisplayString(String[] children);  

一個例子:判斷array是否包含某個值。

/*** Eclipse Class Decompiler plugin, copyright (c) 2016 Chen Chao (cnfree2000@hotmail.com) ***/
package org.apache.hadoop.hive.ql.udf.generic;

import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.hive.ql.exec.UDFArgumentException;
import org.apache.hadoop.hive.ql.exec.UDFArgumentTypeException;
import org.apache.hadoop.hive.ql.metadata.HiveException;
import org.apache.hadoop.hive.serde2.objectinspector.ListObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector.Category;
import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspectorUtils;
import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorFactory;
import org.apache.hadoop.io.BooleanWritable;

@Description(name = "array_contains", value = "_FUNC_(array, value) - Returns TRUE if the array contains value.", extended = "Example:\n  > SELECT _FUNC_(array(1, 2, 3), 2) FROM src LIMIT 1;\n  true")
public class GenericUDFArrayContains extends GenericUDF {
    private static final int ARRAY_IDX = 0;
    private static final int VALUE_IDX = 1;
    private static final int ARG_COUNT = 2;
    private static final String FUNC_NAME = "ARRAY_CONTAINS";
    private transient ObjectInspector valueOI;
    private transient ListObjectInspector arrayOI;
    private transient ObjectInspector arrayElementOI;
    private BooleanWritable result;

    public ObjectInspector initialize(ObjectInspector[] arguments) throws UDFArgumentException {
        if (arguments.length != 2) {
            throw new UDFArgumentException("The function ARRAY_CONTAINS accepts 2 arguments.");
        }

        if (!(arguments[0].getCategory().equals(ObjectInspector.Category.LIST))) {
            throw new UDFArgumentTypeException(0, "\"array\" expected at function ARRAY_CONTAINS, but \""
                    + arguments[0].getTypeName() + "\" " + "is found");
        }

        this.arrayOI = ((ListObjectInspector) arguments[0]);
        this.arrayElementOI = this.arrayOI.getListElementObjectInspector();

        this.valueOI = arguments[1];

        if (!(ObjectInspectorUtils.compareTypes(this.arrayElementOI, this.valueOI))) {
            throw new UDFArgumentTypeException(1,
                    "\"" + this.arrayElementOI.getTypeName() + "\"" + " expected at function ARRAY_CONTAINS, but "
                            + "\"" + this.valueOI.getTypeName() + "\"" + " is found");
        }

        if (!(ObjectInspectorUtils.compareSupported(this.valueOI))) {
            throw new UDFArgumentException("The function ARRAY_CONTAINS does not support comparison for \""
                    + this.valueOI.getTypeName() + "\"" + " types");
        }

        this.result = new BooleanWritable(false);

        return PrimitiveObjectInspectorFactory.writableBooleanObjectInspector;
    }

    public Object evaluate(GenericUDF.DeferredObject[] arguments) throws HiveException {
        this.result.set(false);

        Object array = arguments[0].get();
        Object value = arguments[1].get();

        int arrayLength = this.arrayOI.getListLength(array);

        if ((value == null) || (arrayLength <= 0)) {
            return this.result;
        }

        for (int i = 0; i < arrayLength; ++i) {
            Object listElement = this.arrayOI.getListElement(array, i);
            if ((listElement == null)
                    || (ObjectInspectorUtils.compare(value, this.valueOI, listElement, this.arrayElementOI) != 0))
                continue;
            this.result.set(true);
            break;
        }

        return this.result;
    }

    public String getDisplayString(String[] children) {
        assert (children.length == 2);
        return "array_contains(" + children[0] + ", " + children[1] + ")";
    }
}

總結

當寫Hive UDF時揽涮,有兩個選擇:一是繼承 UDF類,二是繼承抽象類GenericUDF饿肺。這兩種實現(xiàn)不同之處是:GenericUDF 可以處理復雜類型參數(shù)蒋困,并且繼承GenericUDF更加有效率,因為UDF class 需要HIve使用反射的方式去實現(xiàn)敬辣。
UDF是作用于一行的雪标。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市溉跃,隨后出現(xiàn)的幾起案子村刨,更是在濱河造成了極大的恐慌,老刑警劉巖撰茎,帶你破解...
    沈念sama閱讀 216,402評論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件嵌牺,死亡現(xiàn)場離奇詭異,居然都是意外死亡龄糊,警方通過查閱死者的電腦和手機逆粹,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來炫惩,“玉大人僻弹,你說我怎么就攤上這事∷拢” “怎么了蹋绽?”我有些...
    開封第一講書人閱讀 162,483評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長筋蓖。 經(jīng)常有香客問我卸耘,道長,這世上最難降的妖魔是什么粘咖? 我笑而不...
    開封第一講書人閱讀 58,165評論 1 292
  • 正文 為了忘掉前任鹊奖,我火速辦了婚禮,結果婚禮上涂炎,老公的妹妹穿的比我還像新娘忠聚。我一直安慰自己设哗,他們只是感情好,可當我...
    茶點故事閱讀 67,176評論 6 388
  • 文/花漫 我一把揭開白布两蟀。 她就那樣靜靜地躺著网梢,像睡著了一般。 火紅的嫁衣襯著肌膚如雪赂毯。 梳的紋絲不亂的頭發(fā)上战虏,一...
    開封第一講書人閱讀 51,146評論 1 297
  • 那天,我揣著相機與錄音党涕,去河邊找鬼烦感。 笑死,一個胖子當著我的面吹牛膛堤,可吹牛的內容都是我干的手趣。 我是一名探鬼主播,決...
    沈念sama閱讀 40,032評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼肥荔,長吁一口氣:“原來是場噩夢啊……” “哼绿渣!你這毒婦竟也來了?” 一聲冷哼從身側響起燕耿,我...
    開封第一講書人閱讀 38,896評論 0 274
  • 序言:老撾萬榮一對情侶失蹤中符,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后誉帅,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體淀散,經(jīng)...
    沈念sama閱讀 45,311評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,536評論 2 332
  • 正文 我和宋清朗相戀三年蚜锨,在試婚紗的時候發(fā)現(xiàn)自己被綠了吧凉。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,696評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡踏志,死狀恐怖阀捅,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情针余,我是刑警寧澤饲鄙,帶...
    沈念sama閱讀 35,413評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站圆雁,受9級特大地震影響忍级,放射性物質發(fā)生泄漏。R本人自食惡果不足惜伪朽,卻給世界環(huán)境...
    茶點故事閱讀 41,008評論 3 325
  • 文/蒙蒙 一轴咱、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦朴肺、人聲如沸窖剑。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至魄揉,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間需了,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評論 1 269
  • 我被黑心中介騙來泰國打工般甲, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留肋乍,地道東北人。 一個月前我還...
    沈念sama閱讀 47,698評論 2 368
  • 正文 我出身青樓敷存,卻偏偏與公主長得像墓造,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子历帚,可洞房花燭夜當晚...
    茶點故事閱讀 44,592評論 2 353

推薦閱讀更多精彩內容