こんにちは。マイクロアドでサーバーサイドエンジニアをしている大澤です。
今回はApache HiveでComplex型(ARRAY, STRUCT, MAP, UNION)を使用している際に発生した問題と解決方法について紹介します。
問題の内容
Hive上に下記の様なテーブルが存在する場合を想定します。
CREATE TABLE example_table ( column1 INT, column2 STRUCT<field:INT>, column3 ARRAY<INT> );
Primitive型は暗黙にNULLが変換されるので下記の様なクエリでは特に問題は起きません。
INSERT INTO example_table SELECT NULL, NAMED_STRUCT("field", 1), ARRAY(1);
ただ、Complex型は各カラムの定義がテーブル定義と完全に一致する必要があるので下記の様なINSERTは行うことが出来ません。*1
INSERT INTO example_table SELECT 1, NULL, NULL;
Error: Error while compiling statement: FAILED: SemanticException Line 0:-1 Cannot insert into target table because column number/types are different 'example_table': Cannot convert column 1 from void to struct<field:int>. (state=42000,code=40000)
型の一致が求められる場合にはCAST構文を使用すると思いますが、HiveのCASTはPrimitive型にしか対応していないので実行することが出来ません。*2
INSERT INTO example_table SELECT 1, CAST(NULL AS STRUCT<field:INT>), CAST(NULL AS ARRAY<INT>);
Error: Error while compiling statement: FAILED: ParseException line 1:42 cannot recognize input near 'struct' '<' 'field' in primitive type specification (state=42000,code=40000)
問題の解決方法
IF関数を使用するとNULLを該当のComplex型として認識させることができるのでComplex型をNULLにすることができます。*3
INSERT INTO example_table SELECT 1, IF(FALSE, NAMED_STRUCT('field', 1), NULL), IF(FALSE, ARRAY(2), NULL);
参考資料
https://issues.apache.org/jira/browse/HIVE-4022
*1:Hiveの実装で型が完全一致しない場合はPrimitive型以外エラーになる箇所
https://github.com/apache/hive/blob/dc8d8e134c2cc752e89d1b6ccf3097c8e43aa88a/ql/src/java/org/apache/hadoop/hive/ql/parse/SemanticAnalyzer.java#L8433
https://github.com/apache/hive/blob/dc8d8e134c2cc752e89d1b6ccf3097c8e43aa88a/ql/src/java/org/apache/hadoop/hive/ql/parse/SemanticAnalyzer.java#L8170
*2:Hiveの実装でANTLRを使用してCAST構文の定義が行われている箇所。Primitive型のみを受け付けている
https://github.com/apache/hive/blob/dc8d8e134c2cc752e89d1b6ccf3097c8e43aa88a/ql/src/java/org/apache/hadoop/hive/ql/parse/IdentifiersParser.g#L250
*3:Hiveの実装では該当UDFで引数から戻り値の型を推測しているが、NULLは特別扱いなので不一致でもエラーにならずNULL以外の型(今回はComplex型)が使用される
https://github.com/apache/hive/blob/dc8d8e134c2cc752e89d1b6ccf3097c8e43aa88a/ql/src/java/org/apache/hadoop/hive/ql/udf/generic/GenericUDFIf.java
https://github.com/apache/hive/blob/dc8d8e134c2cc752e89d1b6ccf3097c8e43aa88a/ql/src/java/org/apache/hadoop/hive/ql/udf/generic/GenericUDFUtils.java#L142