Apache Hiveにハマり続けている毎日
私自身はHiveなんていらないんですよ...テキストファイルを自前でパースして集計したり統計取ったり,データを学習させるのが仕事なんですが,自分でプログラム組んだ方が早いので.
でも,どうしてもSQLライクなアクセス方法は,会社では捨てられないです.なので,入ってくるデータをせっせとHiveに入れているわけです.
そこで今日,ハマったのはたくさんあるのですが,大きくは二点.
シェルスクリプトとシェルコマンドラインの違いに気をつけよう
Sqoopで,MySQLからHiveにスキーマだけ転送しようとしました.
普段はシェルスクリプトの中に,次のようなコマンドを埋め込んでいました.
sqoop import --connect "jdbc:mysql://mysqlserver:3306/testDB" --username user1 --password pass1 --query "SELECT * FROM users WHERE \$CONDITIONS" --split-by id --target-dir users --hive-table users --hive-database test --hive-import --hive-drop-import-delims --fields-terminated-by \001
ところが,今回,単発作業だったので,bashの上で同じコマンドを打ち込みました.
$ sqoop import --connect "jdbc:mysql://mysqlserver:3306/testDB" --username user1 --password pass1 --query "SELECT * FROM users WHERE \$CONDITIONS" --split-by id --target-dir users --hive-table users --hive-database test --hive-import --hive-drop-import-delims --fields-terminated-by \001
結果を確認.
$ hive --database=test -e "select * from users limit 1" id name NULL NULL
入ってない...
ファイルを直接確認.
$ hdfs dfs -cat /user/hive/warehouse/test.db/users/* | head -1 1^Afoo
入っています.
分かったのは,データベースのプロパティを確認したとき.
$ hive --database=test -e "describe extended users" (中略) parameters:{serialization.format=0, line.delim= , field.delim=0})
CTRL-Aのはずのfield.delimが数字のゼロになっている...bashコマンドラインがエスケープを解釈しちゃいました.
解釈しないように,シングルクオートするのが正解.
$ sqoop import --connect "jdbc:mysql://mysqlserver:3306/testDB" --username user1 --password pass1 --query "SELECT * FROM users WHERE \$CONDITIONS" --split-by id --target-dir users --hive-table users --hive-database test --hive-import --hive-drop-import-delims --fields-terminated-by '\001'
非表示文字なので,こう出るのが正解.
$ hive --database=stockgear -e "describe extended aishipr_items"|cat -t (中略) parameters:{serialization.format=^A, line.delim=^I , field.delim=^A})
catを通さないと,空白になる感じ.
予約語に気をつけよう
Hiveは思ったより予約語が多いです.
SqoopでMySQL(MariaDB)からHDFSに転送したデータを,Hiveのパーティションを追加したテーブルを作ろうと思ってこんなクエリを打ちました.
$ hive --database=test -e "LOAD DATA LOCAL INPATH '/tmp/test' INTO TABLE items PARTITION(dt='2014-06-07')"
ところが,こんなエラーが出ます.
FAILED: ParseException line 1:43 mismatched input 'items' expecting Identifier near 'TABLE' in table name
Frequently Asked Questions | Treasure Data
The following are the reserved keywords in Hive:
TRUE, FALSE, ALL, AND, OR, NOT, LIKE, ASC, DESC, ORDER, BY, GROUP, WHERE,
FROM, AS, SELECT, DISTINCT, INSERT, OVERWRITE, OUTER, JOIN, LEFT, RIGHT,
FULL, ON, PARTITION, PARTITIONS, TABLE, TABLES, TBLPROPERTIES, SHOW, MSCK,
DIRECTORY, LOCAL, TRANSFORM, USING, CLUSTER, DISTRIBUTE, SORT, UNION, LOAD,
DATA, INPATH, IS, NULL, CREATE, EXTERNAL, ALTER, DESCRIBE, DROP, REANME, TO,
COMMENT, BOOLEAN, TINYINT, SMALLINT, INT, BIGINT, FLOAT, DOUBLE, DATE,
DATETIME, TIMESTAMP, STRING, BINARY, ARRAY, MAP, REDUCE, PARTITIONED,
CLUSTERED, SORTED, INTO, BUCKETS, ROW, FORMAT, DELIMITED, FIELDS, TERMINATED,
COLLECTION, ITEMS, KEYS, LINES, STORED, SEQUENCEFILE, TEXTFILE, INPUTFORMAT,
OUTPUTFORMAT, LOCATION, TABLESAMPLE, BUCKET, OUT, OF, CAST, ADD, REPLACE,
COLUMNS, RLIKE, REGEXP, TEMPORARY, FUNCTION, EXPLAIN, EXTENDED, SERDE, WITH,
SERDEPROPERTIES, LIMIT, SET, TBLPROPERTIES
itemsなんて,どんなデータベースでも出そうな単語が予約語になってました...
解決方法は,
If you encounter a reserved keyword issue in your query, please wrap the infringing keyword with ‘`’ as shown below.
SELECT `keyword_column`, COUNT(1) AS cnt FROM table_name GROUP BY `keyword_column`
とのこと.
$ hive --database=test -e "LOAD DATA LOCAL INPATH '/tmp/test' INTO TABLE \`items\` PARTITION(dt='2014-06-07')"
こんな感じで解決出来ました.これもbashコマンドラインと,スクリプトでエスケープキャラクタの個数なんかが変わるので,気をつけて下さい.