文章轉自: http://www.chinaovo.net/hive/295.htm
Hive 是一個很開放的系統,很多內容都支持用戶定製,包括:
- 文件格式:Text File,Sequence File
- 內存中的數據格式: Java Integer/String, Hadoop IntWritable/Text
- 用戶提供的 map/reduce 腳本:不管什麼語言,利用 stdin/stdout 傳輸數據
- 用戶自定義函數: Substr, Trim, 1 – 1
- 用戶自定義聚合函數: Sum, Average…… n – 1
File Format
TextFile | SequenceFIle | RCFFile | |
Data type | Text Only | Text/Binary | Text/Binary |
Internal Storage Order | Row-based | Row-based | Column-based |
Compression | File Based | Block Based | Block Based |
Splitable | YES | YES | YES |
Splitable After Compression | No | YES | YES |
CREATE TABLE mylog ( user_id BIGINT, page_url STRING, unix_time INT) STORED AS TEXTFILE;
當用戶的數據文件格式不能被當前 Hive 所識別的時候,可以自定義文件格式。可以參考 contrib/src/java/org/apache/hadoop/hive/contrib/fileformat/base64 中的例子。寫完自定義的格式後,在創建表的時候指定相應的文件格式就可以:
CREATE TABLE base64_test(col1 STRING, col2 STRING) STORED AS INPUTFORMAT 'org.apache.hadoop.hive.contrib. fileformat.base64.Base64TextInputFormat' OUTPUTFORMAT 'org.apache.hadoop.hive.contrib. fileformat.base64.Base64TextOutputFormat';
SerDe
SerDe 是 Serialize/Deserilize 的簡稱,目的是用於序列化和反序列化。序列化的格式包括:
- 分隔符(tab、逗號、CTRL-A)
- Thrift 協議
反序列化(內存內):
- Java Integer/String/ArrayList/HashMap
- Hadoop Writable 類
- 用戶自定義類
其中,LazyObject 只有在訪問到列的時候才進行反序列化。 BinarySortable:保留了排序的二進制格式。
當存在以下情況時,可以考慮增加新的 SerDe:
- 用戶的數據有特殊的序列化格式,當前的 Hive 不支持,而用戶又不想在將數據加載至 Hive 前轉換數據格式。
- 用戶有更有效的序列化磁盤數據的方法。
用戶如果想爲 Text 數據增加自定義 Serde ,可以參照 contrib/src/java/org/apache/hadoop/hive/contrib/serde2/RegexSerDe.java 中的例子。RegexSerDe 利用用戶提供的正則表倒是來反序列化數據,例如:
CREATE TABLE apache_log( host STRING, identity STRING, user STRING, time STRING, request STRING, status STRING, size STRING, referer STRING, agent STRING) ROW FORMAT SERDE 'org.apache.hadoop.hive.contrib.serde2.RegexSerDe' WITH SERDEPROPERTIES ( "input.regex" = "([^ ]*) ([^ ]*) ([^ ]*) (-|\\[[^\\]]*\\]) ([^ \"]*|\"[^\"]*\") (-|[0-9]*) (-|[0-9]*)(?: ([^ \"]*|\"[^\"]*\") ([^ \"]*|\"[^\"]*\"))?", "output.format.string" = "%1$s %2$s %3$s %4$s %5$s %6$s %7$s %8$s %9$s";) STORED AS TEXTFILE;
用戶如果想爲 Binary 數據增加自定義的 SerDE,可以參考例子:serde/src/java/org/apache/hadoop/hive/serde2/binarysortable,例如:
CREATE TABLE mythrift_table ROW FORMAT SERDE 'org.apache.hadoop.hive.contrib.serde2.thrift.ThriftSerDe' WITH SERDEPROPERTIES ( "serialization.class" = "com.facebook.serde.tprofiles.full", "serialization.format" = "com.facebook.thrift.protocol.TBinaryProtocol";);
Map/Reduce 腳本(Transform)
用戶可以自定義 Hive 使用的 Map/Reduce 腳本,比如:
FROM ( SELECT TRANSFORM(user_id, page_url, unix_time) USING 'page_url_to_id.py' AS (user_id, page_id, unix_time) FROM mylog DISTRIBUTE BY user_id SORT BY user_id, unix_time) mylog2 SELECT TRANSFORM(user_id, page_id, unix_time) USING 'my_python_session_cutter.py' AS (user_id, session_info);
Map/Reduce 腳本通過 stdin/stdout 進行數據的讀寫,調試信息輸出到 stderr。
UDF(User-Defined-Function)
用戶可以自定義函數對數據進行處理,例如:
add jar build/ql/test/test-udfs.jar; CREATE TEMPORARY FUNCTION testlength AS 'org.apache.hadoop.hive.ql.udf.UDFTestLength'; SELECT testlength(src.value) FROM src; DROP TEMPORARY FUNCTION testlength;
UDFTestLength.java 爲:
package org.apache.hadoop.hive.ql.udf; public class UDFTestLength extends UDF { public Integer evaluate(String s) { if (s == null) { return null; } return s.length(); } }
自定義函數可以重載:
add jar build/contrib/hive_contrib.jar; CREATE TEMPORARY FUNCTION example_add AS 'org.apache.hadoop.hive.contrib.udf.example.UDFExampleAdd'; SELECT example_add(1, 2) FROM src; SELECT example_add(1.1, 2.2) FROM src;
UDFExampleAdd.java:
public class UDFExampleAdd extends UDF { public Integer evaluate(Integer a, Integer b) { if (a = null || b = null) return null; return a + b; } public Double evaluate(Double a, Double b) { if (a = null || b = null) return null; return a + b; } }
%%
在使用 UDF 的時候,會自動進行類型轉換,這個 java 或者 C 中的類型轉換有些類似,比如:
SELECT example_add(1, 2.1) FROM src;
的結果是 3.1,這是因爲 UDF 將類型爲 Int 的參數 “1″ 轉換爲 double。
類型的隱式轉換是通過 UDFResolver 來進行控制的,並且可以根據不同的 UDF 進行不同的控制。
UDF 還可以支持變長的參數,例如 UDFExampleAdd.java:
public class UDFExampleAdd extends UDF { public Integer evaluate(Integer... a) { int total = 0; for (int i=0; i<a.length; i++) if (a[i] != null) total += a[i]; return total; } // the same for Double public Double evaluate(Double... a) }
使用例子爲:
SELECT example_add(1, 2) FROM src; SELECT example_add(1, 2, 3) FROM src; SELECT example_add(1, 2, 3, 4.1) FROM src;
綜上,UDF 具有以下特性:
- 用 java 寫 UDF 很容易。
- Hadoop 的 Writables/Text 具有較高性能。
- UDF 可以被重載。
- Hive 支持隱式類型轉換。
- UDF 支持變長的參數。
- genericUDF 提供了較好的性能(避免了反射)。
UDAF(User-Defined Aggregation Funcation)
例子:
SELECT page_url, count(1), count(DISTINCT user_id) FROM mylog;
UDAFCount.java:
public class UDAFCount extends UDAF { public static class Evaluator implements UDAFEvaluator { private int mCount; public void init() { mcount = 0; } public boolean iterate(Object o) { if (o!=null) mCount++; return true; } public Integer terminatePartial() { return mCount; } public boolean merge(Integer o) { mCount += o; return true; } public Integer terminate() { return mCount; } }
UDAF 總結:
- 編寫 UDAF 和 UDF 類似
- UDAF 可以重載
- UDAF 可以返回複雜類
- 在使用 UDAF 的時候可以禁止部分聚合功能