Hive 的可拓展性

 文章轉自: 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 類
  • 用戶自定義類

目前存在的 Serde 見下圖:

其中,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 的時候可以禁止部分聚合功能

UDF,UDAF 和 MR 腳本的對比:

 

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