Hive 定義済み関数でできない集計処理は、まず Reflect 関数を試す


概要

Hadoop/Hive で集計を行う際、定義済み関数で実現できない集計処理は カスタムUDF を作成したり、結果を出力してから別プログラムで処理したり、といった方法で対応することになります
が、別コードを書く手間もありますし管理も面倒なので、Hiveクエリ内で処理できれば楽です

実行したい処理が 既存のJavaクラスで対処できる場合、Hive の Reflect関数によって、独自のラッパーを書かず実現できる かもしれません

環境

Hive 0.9以上(検証環境は 2.1.0)

Reflect UDF

https://cwiki.apache.org/confluence/display/Hive/ReflectUDF
Javaリフレクションを使用してオブジェクトのメソッドをインスタンス化して呼び出します.
静的関数を呼び出すこともできます.

このメソッドは、プリミティブ型またはHiveが直列化する方法を知っている型を返す必要があります.

基本


reflect(class, method[, arg1[, arg2..]])

事例 1. 文字列/数値処理

例は定義済み関数で実現できる機能ですが、
java のクラスに実装されている処理を自由に呼び出せるので、かゆいところにも手が届きます


SELECT reflect("java.lang.String", "valueOf", 1),
       reflect("java.lang.String", "isEmpty"),
       reflect("java.lang.Math", "max", 2, 3),
       reflect("java.lang.Math", "min", 2, 3),
       reflect("java.lang.Math", "round", 2.5),
       reflect("java.lang.Math", "exp", 1.0),
       reflect("java.lang.Math", "floor", 1.9),
       reflect("java.lang.Math", "abs", -10)
FROM src LIMIT 1;


1       true    3       2       3       2.718281828459045       1.0     10

https://docs.oracle.com/javase/jp/8/docs/api/java/lang/String.html
https://docs.oracle.com/javase/jp/8/docs/api/java/lang/Math.html

事例 2. URLエンコード/デコード

検索結果画面のURLなどでは ユーザの自由入力文字列(検索文字列)が含まれますが、検索文字列は通常URLエンコードされた状態でログに記録されるので、分析者が読める文字列にデコードする処理は便利です.
この処理を組み合わせることで、アクセスログから検索文字列ランキングなどの生成がいちクエリで完結 します

処理内容がシンプルなため、reflect 関数を使うのに最適なケースといえます


SELECT 
  encoded_url,
  reflect("org.apache.commons.codec.net.URLCodec", "decode", encoded_url, "UTF-8"), 
  reflect("java.net.URLDecoder", "decode", encoded_url, "UTF-8") 
FROM src LIMIT 1;

%E3%83%86%E3%82%B9%E3%83%88%E3%83%A1%E3%83%83%E3%82%BB%E3%83%BC%E3%82%B8        テストメッセージ        テストメッセージ

https://docs.oracle.com/javase/jp/8/docs/api/java/net/URLDecoder.html
https://commons.apache.org/proper/commons-codec/apidocs/org/apache/commons/codec/net/URLCodec.html

事例 3. ハッシュ値生成

Hive 1.3 以降であれば組み込み関数ですでに多くのハッシュ関数が利用できますが、
それ以前のバージョンでも、組み込み関数にない形式を自由に呼び出して生成できます

SELECT
  md5('hoge'), 
  sha2('hoge',256), 
  sha2('hoge',384), 
  sha2('hoge',512),
  reflect('org.apache.commons.codec.digest.DigestUtils', 'md5Hex', 'hoge'), 
  reflect('org.apache.commons.codec.digest.DigestUtils', 'sha256Hex', 'hoge'), 
  reflect('org.apache.commons.codec.digest.DigestUtils', 'sha384Hex', 'hoge'), 
  reflect('org.apache.commons.codec.digest.DigestUtils', 'sha512Hex', 'hoge')
from src LIMIT 1;

ea703e7aa1efda0064eaa507d9e8ab7e 
ecb666d778725ec97307044d642bf4d160aabb76f56c0069c71ea25b1e926825  cc2aa04a6cb251b8d9dfbacc60b806587456d3fc356dc832116b9ba188713e6adf5f995b750d86b0883b24d07a37c720 dbb50237ad3fa5b818b8eeca9ca25a047e0f29517db2b25f4a8db5f717ff90bf0b7e94ef4f5c4e313dfb06e48fbd9a2e40795906a75c470cdb619cf9c2d4f6d9 

ea703e7aa1efda0064eaa507d9e8ab7e 
ecb666d778725ec97307044d642bf4d160aabb76f56c0069c71ea25b1e926825 cc2aa04a6cb251b8d9dfbacc60b806587456d3fc356dc832116b9ba188713e6adf5f995b750d86b0883b24d07a37c720 dbb50237ad3fa5b818b8eeca9ca25a047e0f29517db2b25f4a8db5f717ff90bf0b7e94ef4f5c4e313dfb06e48fbd9a2e40795906a75c470cdb619cf9c2d4f6d9 

https://cwiki.apache.org/confluence/display/Hive/LanguageManual+UDF
https://commons.apache.org/proper/commons-codec/apidocs/org/apache/commons/codec/digest/DigestUtils.html

まとめ

最新バージョンでは組み込み関数も充実していて 不足を感じることはあまりありませんが、
https://cwiki.apache.org/confluence/display/Hive/LanguageManual+UDF

URLエンコード/デコードなど、かゆいところに手が届かない部分はこの先もでてきますし、
UDFをつくるまでもない汎用的/原始的な処理は、手軽に処理したいところです

Reflect 関数を使えば、その手軽さと利便性が享受できそうです

参考