Fenriswolf 程式筆記

奮利斯狼的地盤,小綿羊勿入

自訂 Pig Eval Function – 型別檢查

直接繼承 EvalFunc 預設並沒有強制開發者 override 型別檢查的 functions,這會造成誤用別人所寫的 UDFs。尤其是當讀入 100 萬筆資料卻發生 100 萬次 ClassCastException 後才知道自己傳入錯的型別

1. 先看一個 java 範例
這裡定義了四個 overloading functions 做數字 format 的轉換

public String numberFormat(int number, String pattern) {
  //do something
}

public String numberFormat(long number, String pattern) {
  //do something
}
 
public String numberFormat(float number, String pattern) {
  //do something
}
 
public String numberFormat(double number, String pattern) {
  //do something
}

2. 轉成 Pig UDF 的寫法
override exec function,從範例程式可以看出,取出傳入的參數就是依序讀取 input tuple 的值

@Override
public String exec(Tuple input) throws IOException {
    if (input == null || input.size() < 2) {
        log.warn("invalid number of arguments");
        return null;
    }

    try {
        Double number = DataType.toDouble(input.get(0));
        String pattern = (String) input.get(1);            
        DecimalFormat df = new DecimalFormat(pattern);
        return df.format(number);
    } catch (NumberFormatException nfe) {
        log.error("Failed to process input; error - " + nfe.getMessage());
        return null;
    } catch (Exception e) {
        log.error(e.getMessage());
        return null;
    }
}

3. 定義傳入值
override getArgToFuncMapping function 並回傳一個 FuncSpec list
FuncSpec 定義了可接受的傳入值 (Integer, String), (Long, String), (Float, String) 和 (Double, String)

@Override
public List<FuncSpec> getArgToFuncMapping() throws FrontendException {
    List<FuncSpec> funcList = new ArrayList<FuncSpec>();

    funcList.add(SchemaUtils.getFuncSpecByTypes(this, DataType.INTEGER, DataType.CHARARRAY));
    funcList.add(SchemaUtils.getFuncSpecByTypes(this, DataType.LONG, DataType.CHARARRAY));
    funcList.add(SchemaUtils.getFuncSpecByTypes(this, DataType.FLOAT, DataType.CHARARRAY));
    funcList.add(SchemaUtils.getFuncSpecByTypes(this, DataType.DOUBLE, DataType.CHARARRAY));

    return funcList;
}

因為 Pig 定義 schema 的方式很麻煩,這邊用了我寫的 SchemaUtils 來簡化這個步驟,在程式下載區可以找到 SchemaUtils 的原始碼

4. 定義回傳值
override outputSchema function ,並定義回傳值為 String

@Override
public Schema outputSchema(Schema input) {
    return new Schema(new Schema.FieldSchema(null, DataType.CHARARRAY));
}

5. 測試
寫一個錯誤的 pig script 測試型別檢查的功能

A = LOAD 'test.txt' USING PigStorage as (nonnumber: chararray);
B = FOREACH A GENERATE com.fw.pig.NumberFormat(nonnumber, '0000.00');

不需要執行 DUMP 或 STORE 指令就會發現下面的錯誤訊息
雖然沒有清楚說明參數的型別,但已經阻止我們浪費時間執行錯誤的 pig script

2012-03-19 00:12:58,198 [main] ERROR org.apache.pig.tools.grunt.Grunt - ERROR 1045: 
<line 2, column 23> Could not infer the matching function for com.fw.pig.NumberFormat as multiple or none of them fit. Please use an explicit cast.

 
 
執行環境
CentOS 6.2
JDK 1.6.0_31
Cloudera CDH3U3
Pig 0.9.2

參考資料
Apache Pig Getting Started
Pig Latin Basics
Built In Functions

程式下載
NumberFormat.java
SchemaUtils.java

廣告

2012/04/01 - Posted by | Pig | ,

仍無迴響。

發表迴響

在下方填入你的資料或按右方圖示以社群網站登入:

WordPress.com Logo

您的留言將使用 WordPress.com 帳號。 登出 / 變更 )

Twitter picture

您的留言將使用 Twitter 帳號。 登出 / 變更 )

Facebook照片

您的留言將使用 Facebook 帳號。 登出 / 變更 )

Google+ photo

您的留言將使用 Google+ 帳號。 登出 / 變更 )

連結到 %s

%d 位部落客按了讚: