S-JIS[2011-08-12/2011-09-14] 変更履歴

Hiveユーザー定義関数

Hiveのユーザー定義関数(User Defined Function:UDF)の作り方のメモ。


クラス作成

Hiveで使う関数を作るには、org.apache.hadoop.hive.ql.exec.UDFを継承したクラスを作成し、「evaluate」という名前のメソッドを用意する。
Hive上で自作関数を実行すると、このevaluateメソッドが呼ばれる。
(『Hadoop徹底入門』p.224には「evaluateメソッドを継承する」と書かれているが、親クラスにevaluateというメソッドが定義されているわけではないので、「継承」と言うと語弊がある気がする)

evaluateメソッドの引数や戻り型は自由。
Hive上で呼び出すときにそれらに応じた型の値を指定することになる。

package sample;

import org.apache.hadoop.hive.ql.exec.UDF;
public class SampleUDF extends UDF {

	public String evaluate(String s) {
		return s + s;
	}
}

使用できるデータ型


必要となるjarファイルは以下の通り。

jarファイル 備考 Eclipseのソースの添付
HIVE_HOME/lib/hive-exec-0.7.1.jar UDFクラス C:/cygwin/usr/local/hive-0.7.1/src
HADOOP_HOME/hadoop-0.20.2-core.jar HadoopのTextやIntWritable等を使う場合 C:/cygwin/usr/local/hadoop-0.20.2/src

jarファイル化

Hiveにはjarファイルを読み込ませるので、作ったクラスをjarファイル化しておく。

プロジェクト/bin/build.xml:

<?xml version="1.0" encoding="Shift_JIS"?>
<project name="hive0.7.1" default="jar" basedir=".">
	<property name="src" location="../src" />
	<property name="classes" location="../classes" />

	<target name="jar">
		<jar jarfile="C:/cygwin/tmp/hiveudf.jar">
			<fileset dir="${classes}" includes="**/*.class" />
			<fileset dir="${src}" includes="**/*.java" />
		</jar>
	</target>
</project>

ユーザー定義関数の使用

Hiveから自作のユーザー定義関数を使用するには、まずクラスの入ったjarファイルを読み込ませ、
CREATE TEMPORARY FUNCTIONによって関数名(とクラス名)を定義する。

hive> add jar C:/cygwin/tmp/hiveudf.jar;
Added C:/cygwin/tmp/hiveudf.jar to class path
Added resource: C:/cygwin/tmp/hiveudf.jar

※追加したjarファイルは「list jars;」で一覧表示、「delete jar ファイル名;」で除去できる。

hive> create temporary function myfunc as 'sample.SampleUDF';
OK
hive> select myfunc(項目) from テーブル;

※関数はDROP TEMPORARY FUNCTIONで削除できる。


関数定義の確認方法

自作のユーザー定義関数もSHOW FUNCTIONSやDESCRIBE FUNCTIONによって確認できる。
(SHOW FUNCTIONSには、正規表現で関数名のパターンを指定することが出来る。SHOW TABLESと同様)

hive> show functions 'm.*';
OK
map
max
min
minute
month
myfunc
hive> desc function myfunc;
OK
There is no documentation for function 'myfunc'

ドキュメントが無いと言われた^^;


ドキュメント(関数の説明)ユーザー定義関数クラスのアノテーションで記述する。

import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.hive.ql.exec.UDF;
@Description(name = "sample-name", value = "_FUNC_ sample-description", extended = "sample-extended")
public class SampleUDF extends UDF {
	〜
}

Descriptionアノテーションのvalueに概要、extendedに詳細(使用例など)を記述する。
valueやextended内に「_FUNC_」というキーワードを入れると、create functionで指定した関数名に置換される。

hive> desc function myfunc;
OK
myfunc sample-description

hive> desc function extended myfunc;
OK
myfunc sample-description
sample-extended

UDFの詳細

ユーザー定義関数クラス内のevaluateメソッドはオーバーロードすることが出来る。(引数違いのメソッドを定義できる)
Hiveから使う際は引数に応じて正しいevaluateメソッドが呼ばれる。(引数の個数が不定な可変長引数も可)

対応するデータ型
Hiveのデータ型 UDFで使える型 更新日
string java.lang.String
Text
 
int int
java.lang.Integer
IntWritable
 
double double
java.lang.Double
DoubleWritable
 
boolean boolean
java.lang.Boolean
BooleanWritable
 
array<型> java.util.List<型>  
map<キー型, 値型> java.util.Map<キー型, 値型>  
struct class 2011-09-14
public class SampleUDF2 extends UDF {

	public Map<String, Integer> evaluate(String key, int value) {
		Map<String, Integer> map = new HashMap<String, Integer>();
		map.put(key, value);
		return map;
	}

	public List<String> evaluate(String... values) {
		return Arrays.asList(values);
	}
}
hive> create temporary function sample2 as 'sample.SampleUDF2';
hive> select sample2('key', 123), sample2('a', 'b', 'c') from テーブル;

booleanを返すevaluateメソッドを作れば、where句に直接指定することも出来る。

public class BooleanUDF extends UDF {

	public boolean evaluate(int n, int m) {
		return n == m;
	}
}
hive> create temporary function sample3 as 'sample.BooleanUDF';
hive> select 't' from テーブル where sample3(123, 123);

戻り型の例

evaluateの戻り値の型とHiveQLでの使い方の例。[2011-09-14]

  UDF HiveQL 備考
配列 public List<String> evaluate() {
  List<String> list = new ArrayList<String>();
  list.add("foo");
  list.add("bar");
  list.add("zzz");
  return list;
}
select a[0], a[1], a[2] from(
  select udf() a from dual
) t;
Listを返すと、HiveQLでは配列になる。
マップ public Map<String, String> evaluate() {
  Map<String, String> map = new HashMap<String, String>();
  map.put("abc", "foo");
  map.put("def", "bar");
  map.put("ghi", "zzz");
  return map;
}
select m['abc'], m['def'], m['ghi'] from(
  select udf() m from dual
) t;
Mapを返すと、HiveQLでもマップになる。
構造体 static class Sample {
  private String abc;
  private String def;
  private String ghi;
}

public Sample evaluate() {
  Sample bean = new Sample();
  bean.abc = "foo";
  bean.def = "bar";
  bean.ghi = "zzz";
  return bean;
}
select s.abc, s.def, s.ghi from(
  select udf() s from dual
) t;
クラスを返すと、HiveQLではStructになる。
クラスのフィールドが構造体の各要素の名称となる。
各フィールドがpublicである必要は無いし、
getterやsetterメソッドがあっても関係ない。

HiveQLへ戻る / Hive目次へ戻る / 技術メモへ戻る
メールの送信先:ひしだま