久しぶりにMapReduceじゃなくてタダのJavaを書いたらハマった話

Apache HiveのオフィシャルWikiのサンプルをコピペして,JDBC経由でJavaからリモートのhive serverにアクセスしようと思ったわけですよ.
HiveClient - Apache Hive - Apache Software Foundation


まず準備部分だけ.こんな感じでイケるはず.

public class HiveClientDriver {
private static String driverName = "org.apache.hadoop.hive.jdbc.HiveDriver";
  public static void main(String[] args) {
    System.out.println("classpath=" + System.getProperty("java.class.path"));
    try {
      Class.forName(driverName);
    } catch (ClassNotFoundException e) {
      e.printStackTrace();
      System.exit(1);
    }
    System.out.println("END");
  }
}

しかし既にハマる.

コンパイルして実行.

% javac HiveClientDriver.java
% java HiveClientDriver
classpath=.
java.lang.ClassNotFoundException: org.apache.hadoop.hive.jdbc.HiveDriver
        at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
        at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:425)
        at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:358)
        at java.lang.Class.forName0(Native Method)
        at java.lang.Class.forName(Class.java:190)
        at HiveClientDriver.main(HiveClientDriver.java:6)

そりゃそーですよねーHiveのライブラリにクラスパスが通ってませんよねー.
オプションで指定する.

% java -cp .:/usr/local/hive/lib/hive-jdbc-0.10.0-cdh4.4.0.jar HiveClientDriver
classpath=.:/usr/local/hive/lib/hive-jdbc-0.10.0-cdh4.4.0.jar
END

OK.次にjarにしてやってみる.

まず,jarに詰めると同時にマニフェストにmain関数があるクラスを登録.

% jar cvfe HiveClientDriver.jar HiveClientDriver HiveClientDriver.class 
マニフェストが追加されました
HiveClientDriver.classを追加中です(入=1110)(出=646)(41%収縮されました)

最初に作ったコンパイル後のクラスファイルが悪さするといけないので消す.

% rm -v HiveClientDriver.class 
HiveClientDriver.class

そしてクラスパスの指定を敢えてしないでエラーを確認しながら実行.

% java HiveClientDriver
エラー: メイン・クラスHiveClientDriverが見つからなかったかロードできませんでした
% java -cp . HiveClientDriver
エラー: メイン・クラスHiveClientDriverが見つからなかったかロードできませんでした
 % java -jar HiveClientDriver.jar  HiveClientDriver
classpath=HiveClientDriver.jar
java.lang.ClassNotFoundException: org.apache.hadoop.hive.jdbc.HiveDriver
        at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
        at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:425)
        at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:358)
        at java.lang.Class.forName0(Native Method)
        at java.lang.Class.forName(Class.java:190)
        at HiveClientDriver.main(HiveClientDriver.java:6)
% java -cp /usr/local/hive/lib/hive-jdbc-0.10.0-cdh4.4.0.jar -jar HiveClientDriver.jar HiveClientDriver
classpath=HiveClientDriver.jar
java.lang.ClassNotFoundException: org.apache.hadoop.hive.jdbc.HiveDriver
        at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
        at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:425)
        at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:358)
        at java.lang.Class.forName0(Native Method)
        at java.lang.Class.forName(Class.java:190)
        at HiveClientDriver.main(HiveClientDriver.java:6)

ここで一瞬ハマる.
クラスパスの指定とjarの指定のオプションを同時に指定してしまって,-cpの指定は無視されていることがclasspath=の表示から分かります.
2006-09-08

クラスパス指定だけにして,やっと成功.

% java -cp /usr/local/hive/lib/hive-jdbc-0.10.0-cdh4.4.0.jar:HiveClientDriver.jar HiveClientDriver
classpath=/usr/local/hive/lib/hive-jdbc-0.10.0-cdh4.4.0.jar:HiveClientDriver.jar
END

このあと,Rubyでクラスパスの探索やjavaを実行するスクリプトを書いたのですが,ちょっとハマりました.

オフィシャルWiki

# from hadoop/build
# hadoop-*-core.jar

と書いてあったので,適当に似たファイル名を探してcoreって入ってりゃいいだろーと思って

hadoop_core = "#{hadoop_home}/share/hadoop/mapreduce/hadoop-mapreduce-client-core-2.0.0-cdh4.5.0.jar" 

とやると,

Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/hadoop/io/Writable
        at org.apache.hadoop.hive.jdbc.HiveStatement.executeQuery(HiveStatement.java:198)
        at org.apache.hadoop.hive.jdbc.HiveStatement.execute(HiveStatement.java:132)

と基本的なクラスが無いと言われました.正解はこっち.

hadoop_core = "#{hadoop_home}/share/hadoop/common/hadoop-common-2.0.0-cdh4.5.0.jar"