SqoopでOracleからHiveにインポートするのにハマる
登場人物は以下です.
Oracle JDBC ドライバ
JDBC/UCP Download Page
Apache Hive
Apache Hive TM
ログやデータベースは沢山あります.HDFSか何かにデータを集約したいと思っています.
MySQLとMicrosoft SQL Serverについては多少のノウハウが溜まってきていました.
SqoopでMySQLからHadoop+Hiveにパーテション作成しながらデータ転送,ベンチマーク付き - なぜか数学者にはワイン好きが多い
Apache Sqoopにハマる - なぜか数学者にはワイン好きが多い
今回は,Oracleでハマりました.
いくつかありました...
表示するだけでも日本語が化ける
$ sqoop eval --connect 'jdbc:oracle:thin:@192.168.1.3:2222:USERDB' --username hoge --password hage --query "select REGDATE, USERNAME FROM USERTABLE where ROWNUM <= 3" ---------------------------------- | REGDATE | USERNAME | ---------------------------------- | 2014-03-09 02:18:47.0 | テNチ[テヘテモチルチ | | 2014-03-09 02:18:52.0 | テNチ[テヘテモチルチ | | 2014-03-09 02:18:54.0 | チルヨヤメチル | ---------------------------------- 14/03/25 18:47:40 WARN tool.EvalSqlTool: SQL exception executing statement: java.sql.SQLException: Could not commit with auto-commit set on at oracle.jdbc.driver.PhysicalConnection.commit(PhysicalConnection.java:4439) at oracle.jdbc.driver.PhysicalConnection.commit(PhysicalConnection.java:4486) at org.apache.sqoop.tool.EvalSqlTool.run(EvalSqlTool.java:78) at org.apache.sqoop.Sqoop.run(Sqoop.java:145) at org.apache.hadoop.util.ToolRunner.run(ToolRunner.java:70) at org.apache.sqoop.Sqoop.runSqoop(Sqoop.java:181) at org.apache.sqoop.Sqoop.runTool(Sqoop.java:220) at org.apache.sqoop.Sqoop.runTool(Sqoop.java:229) at org.apache.sqoop.Sqoop.main(Sqoop.java:238)
HadoopのHiveにimportしようとするとエラーが出る
$ sqoop import --connect 'jdbc:oracle:thin:@192.168.1.3:2222:USERDB' --username hoge --password hage --query "select REGDATE, USERNAME FROM USERTABLE where \$CONDITIONS" --split-by REGDATE --hive-table ORACLE_USERTABLE --hive-import --target-dir ORACLE_USERTABLE 14/03/olumn25 14:52:23 ERROR sqoop.Sqoop: Got exception running Sqoop: java.lang.NullPointerException java.lang.NullPointerException at org.apache.sqoop.hive.TableDefWriter.getCreateTableStmt(TableDefWriter.java:181) at org.apache.sqoop.hive.HiveImport.importTable(HiveImport.java:187) at org.apache.sqoop.tool.ImportTool.importTable(ImportTool.java:425) at org.apache.sqoop.tool.ImportTool.run(ImportTool.java:502) at org.apache.sqoop.Sqoop.run(Sqoop.java:145) at org.apache.hadoop.util.ToolRunner.run(ToolRunner.java:70) at org.apache.sqoop.Sqoop.runSqoop(Sqoop.java:181) at org.apache.sqoop.Sqoop.runTool(Sqoop.java:220) at org.apache.sqoop.Sqoop.runTool(Sqoop.java:229) at org.apache.sqoop.Sqoop.main(Sqoop.java:238)
HadoopのHiveにimportする時のエラーを消しても,文字化けする
$ hive -e 'select * from ORACLE_USERTABLE OK REGDATE USERNAME 2014-03-09 02:18:47 テNチ[テヘテモチルチ 2014-03-09 02:18:52 テNチ[テヘテモチルチ 2014-03-09 02:18:54 チルヨヤメチル
まずは,オートコミットの
SQL exception executing statement: java.sql.SQLException: Could not commit with auto-commit set on
です.
これは幸い,グーグル先生に聞いたら解決方法がありました.
org.apache.sqoop.manager.OracleManager.java
に,この一行を加えます.
connection.setAutoCommit(false);
次に,evalコマンドとselect文で表示させる場合です.auto-commitの修正はされていなければなりません.
その上で,org.apache.sqoop.util.ResultSetPrinter.javaのメソッドprintResultSet(PrintWriter pw, ResultSet results)を修正します.
for (int i = 1; i < cols + 1; i++) { if (metadata.getColumnType(i) == Types.VARCHAR) { printPadded(sb, new String(results.getBytes(i), "MS932"), colWidths[i - 1]); sb.append(COL_SEPARATOR); }else { printPadded(sb, results.getString(i), colWidths[i - 1]); sb.append(COL_SEPARATOR); } }
型がVARCHARだった時だけ,無理やりコード変換をします.
最後,importする時も,型がVARCHARだったらコード変換します.
変更するのは,org.apache.sqoop.lib.JdbcWritableBridge.javaのメソッドreadString(int colNum, ResultSet r)です.
public static String readString(int colNum, ResultSet r) throws SQLException, UnsupportedEncodingException { return new String(r.getBytes(colNum),"MS932"); }
そしてantでビルドして下さい.
$ sqoop import --connect 'jdbc:oracle:thin:@192.168.1.3:2222:USERDB' --username hoge --password hage --query "select REGDATE, USERNAME FROM USERTABLE where \$CONDITIONS" --split-by REGDATE --hive-table ORACLE_USERTABLE --hive-import --target-dir ORACLE_USERTABLE $ hive -e 'select * from ORACLE_USERTABLE OK REGDATE USERNAME 2014-03-09 02:18:47 ほげほげ♪ 2014-03-09 02:18:52 ほげほげ♪ 2014-03-09 02:18:54 ☆はげはげ☆
このWindowsのMS932に特化したコードは,同僚ともう少し検証したあとに公開する予定です.