uokadaの見逃し三振は嫌いです

ここで述べられていることは私の個人的な意見に基づくものであり、私が所属する組織には一切の関係はありません。

hive-exec.jarを利用する際のTips

仕事で作っていたアプリケーションでhive-execを利用する機会があり、その過程で色々とハマったので解決方法を残しておきます。

java.lang.NoSuchMethodErrorへの対応

アプリケーションを開発し無事にアプリを立ち上げたが実行中にjava.lang.NoSuchMethodErrorを吐いて処理が失敗しました。

java.lang.NoSuchMethodError: 
  'void com.google.common.base.Preconditions.checkArgument(boolean, java.lang.String, java.lang.Object)'

このとき利用していたのがhive-exec-2.3.2-jarで何故このエラーが出るのかを調べていきます。

まず、jarファイルをダウンロードして中を調べてみるとjarファイルにGoogle guava関連のクラスが含まれていることが分かります。

$ jar tvf hive-exec-2.3.2.jar|grep Preconditions
  2059 Thu Nov 09 14:29:18 JST 2017 org/apache/parquet/Preconditions.class
  5310 Thu Nov 09 14:29:18 JST 2017 com/google/common/base/Preconditions.class
  2704 Thu Nov 09 14:29:20 JST 2017 com/google/common/math/MathPreconditions.class

$ jar tvf hive-exec-2.3.2.jar |grep "guava"   
     0 Thu Nov 09 14:29:18 JST 2017 META-INF/maven/com.google.guava/
     0 Thu Nov 09 14:29:18 JST 2017 META-INF/maven/com.google.guava/guava/
   131 Thu Nov 09 14:29:18 JST 2017 META-INF/maven/com.google.guava/guava/pom.properties
  5376 Thu Nov 09 14:29:18 JST 2017 META-INF/maven/com.google.guava/guava/pom.xml

今回のエラーは十中八九これが原因と思われました。なので、guava関連のファイルを取り除いたhive-exec.jarを利用すれば問題が解決するように思いました。

幸いなことに、hive-execライブラリは通常のjarファイル以外にもcore.jarというのが提供されています。

このcore.jarファイルは依存ライブラリのクラスが全く入っておらずorg.apache.hive関連のファイルしか含まれていないjarファイルです。
念の為、このjarファイルをダウンロードして中身を確認してみるとguava関連のクラスが入ってないことが分かります。

$ jar tvf hive-exec-2.3.2-core.jar |grep Preconditions
<no output>

このjarを使えば最初の例外を発生させずにアプリケーションを実行することが出来そうです。

余談: core.jarはいつから提供されているのか? & Why is the core.jar provided?

ここは完全に余談ですがcore.jarはいつから提供されているのかと何故提供されるようになったのかについて見ておきます。

ここ から過去のバージョンをいくつかみていつから提供されているのか調べます。

調べていくとv0.14.0からcore.jarが提供されていました。

次は、この時期のissueを読んで提供された理由を調べていきます。ググったらすぐ該当するissueが見つかりました。

How to use the core.jar in maven, gradle and sbt

さて、core.jarが提供されていることが分かりましたがどうすればこのjarを利用することが出来るのか紹介します。

maven, gradle, sbtの3つでどういう方法でcore.jarを利用するか紹介します。

どれもclassifierタグかキーワードを入れるだけで簡単に利用することが出来ます。

Maven

<dependencies>
    <dependency>
      <groupId>org.apache.hive</groupId>
      <artifactId>hive-exec</artifactId>
      <version>2.3.2</version>
      <classifier>core</classifier>
    </dependency>
</dependencies>

Gradle

    compile("org.apache.hive:hive-exec:2.3.2:core")  
or
  compile(group:'org.apache.hive', name: 'hive-exec', version: '2.3.2', classifier: 'core')

sbt

libraryDependencies += "org.apache.hive" % "hive-exec" % "2.3.2" classifier "core"

or

"org.apache.hive" % "hive-exec" % "2.3.2" classifier "core"

まとめ

自分のケースではcore.jarを利用してアプリケーションを再コンパイル・パッケージングして動かして確認したところ例外が発生しなくなり期待通り動作するようになりました。

今回は hive-execを利用する際に起きたトラブルとその解決方法について紹介しました。
自分はこれまでclassifierされたjarを利用することがなかったのでcore.jarが提供されている可能性やそのjarファイルの利用方法を調べるのに時間を取られ問題を解決するまでかなりの時間を要しました。
今後同じようなケースがあった場合にサクッとclassifierされたjarファイルが存在する可能性を調べてデバッグを高速に完了出来るのではないかと思います。 また、このエントリーが他のhive-execを利用するユーザーの助けになればと思います。