【Scala】実行可能なJARの作成(開発環境はEclipse)

Scalaは基本コンパイルして動かす言語ですが、標準の機能としてShellのようにコマンドから実行することも可能です。(ただその場合も結局裏側でコンパイルして動いています。)

運用や検証時など手動で処理を実行する場合は、コマンドラインから実行するだけで事足りますが、ほかのシステムと連携したり、プログラムとして組み込む場合は別の方法で実行する必要があります。

実行方法としては一つの機能をJARファイルに固めて実行する形となります。今回はSparkでプログラミングした時の構成を例に説明します。(Sparkは裏側はScalaで動かしています。)

設定する中でエラーになったことに関して、そのままの流れで説明していきます。さらにメモ書きベースになっているのでご注意ください。

ディレクトリ構成

まず最初に、最終的なプロジェクトのディレクトリ構成について提示します。
構成は以下の通り。
spark_test/ (プロジェクトトップ)
  |_ project/  
  |   |_ build.properties 
  |   |_ assembly.sbt
  |      ・・・
  |_ src/
  |  |_ main/
  |     |_ scala/
  |          |_ sample/
  |              |_ InsertYm.scala
  |                 ・・・
  |_ target/
  |   |_resolution-cache/
  |   |_streams/
  |   |_scala-2.11/
  |      |_classes/
  |           |_sample-assembly-0.01.jar  (実行可能なJAR)
  |           |_sample-0.01.jar  (実行可能じゃないJAR??)
  |_ build.sbt (sbtビルダーの設定ファイル)

 

設定手順

1.ディレクトリ構成の準備

cd ~/cas_test/spark/ 
mkdir spark_test 
touch spark_test/build.sbt 
touch spark_test/build.sbt 
mkdir spark_test/src 
mkdir spark_test/src/main 
mkdir spark_test/src/main/scala 
mkdir spark_test/src/main/scala/sample 
cp ~/eclipse/workspace/spark_test/src/sample/InsertYmd.scala ~/cas_test/spark/spark_test/src/main/scala/sample/InsertYmd.scala 
cp ~/eclipse/workspace/spark_test/src/sample/InsertYm.scala ~/cas_test/spark/spark_test/src/main/scala/sample/InsertYm.scala 
cp ~/eclipse/workspace/spark_test/src/sample/OutputYmd.scala ~/cas_test/spark/spark_test/src/main/scala/sample/OutputYmd.scala 
cp ~/eclipse/workspace/spark_test/src/sample/OutputYm.scala ~/cas_test/spark/spark_test/src/main/scala/sample/OutputYm.scala 
cp ~/eclipse/workspace/spark_test/src/sample/OutputYmd2.scala ~/cas_test/spark/spark_test/src/main/scala/sample/OutputYmd2.scala 
cp ~/eclipse/workspace/spark_test/src/sample/OutputYm2.scala ~/cas_test/spark/spark_test/src/main/scala/sample/OutputYm2.scala 

 

2.sbtビルダーの設定

sbtのインストール

curl https://bintray.com/sbt/rpm/rpm | sudo tee /etc/yum.repos.d/bintray-sbt-rpm.repo
sudo yum install sbt

vi ~/cas_test/spark_test/build.sbt (暫定版)

name := "spark_test"

version := "0.01"

scalaVersion := "2.11.8"

resolvers += (
    "Local Maven Repository" at "/home/user/.m2/repository/"
)

libraryDependencies ++= Seq(
  "org.apache.spark" % "spark-core_2.11" % "2.1.0"
  ,"org.apache.spark" % "spark-sql_2.11" % "2.1.0"
  ,"org.apache.spark" % "spark-mllib_2.11" % "2.1.0"
  ,"org.apache.spark" % "spark-graphx_2.11" % "2.1.0"
  ,"com.datastax.spark" % "spark-cassandra-connector_2.11" % "2.0.0-M3"
)

 

3.ビルド+jarファイルの作成

sbt clean package

 [エラー1 ビルドがなんかうまくいかない]
  ⇒※オンライン接続した状態にする?
  ⇒build.sbtに記載したライブラリを起動時にネット上から取得しているっぽいから、オンラインの状態で作業する必要がある。

 [エラー2  [error] Modules were resolved with conflicting cross-version suffixes in {file:/home/user/cas_test/spark/spark_test/}spark_test:]
 [error]    org.scala-lang.modules:scala-xml _2.11, _2.12
 ⇒原因は、scalaのバージョン間違い。build.sbtの「scalaVersion := "2.12.1"」
 ⇒「scalaVersion := "2.11.8"」にする
 再度実行したら一様JARファイルは作成された。(ただこのときJARの中にクラスが何も入っていないことは知る由もなかった。。。><;)

 

4.環境変数を通す

~/.bash_profileに[JAVA_HOME]を追記(jvmの場所:/usr/lib/jvm/java-1.6.0-openjdk.x86_64)

# .bash_profile

# Get the aliases and functions
if [ -f ~/.bashrc ]; then
        . ~/.bashrc
fi

# User specific environment and startup programs
# JAVA_HOME=/usr/lib/jvm/java-1.6.0-openjdk.x86_64
JAVA_HOME=/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.111-2.b15.el7_3.x86_64
SPARK_HOME=/usr/local/lib/spark

PATH=$PATH:$HOME/.local/bin:$HOME/bin:$JAVA_HOME/bin:$SPARK_HOME/bin

export PATH
source ~/.bash_profile
 ⇒環境変数が通る

 

5.Jarからプログラムを実行

cd /home/user/cas_test/spark/target/scala-2.10

/usr/local/lib/spark/bin/spark-submit --class sample.InsertYmd  --master local[4] ~/cas_test/spark/spark_test/target/scala-2.11/sample_2.11-0.01.jar

※「sample.InsertYmd」は自分で作ったサンプルソースのクラス名です。詳細は今回登場しません。。。  

 [エラー3  Exception in thread "main" java.lang.NoClassDefFoundError: com/datastax/spark/connector/mapper/ColumnMapper]
  ⇒要は読み込み対象のクラスが存在しない
  ⇒原因としてライブラリ依存が問題で、sbt は [Apache Ivy] を使ってマネージ依存性を実装しているので、eclipseなどでMavenを使用して依存関係を解決している場合クラスがうまく読み込まれない
  ⇒参考:https://www.playframework.com/documentation/ja/2.2.x/SBTDependencies、http://www.scala-sbt.org/0.13/docs/ja/Library-Dependencies.html

 

6.Sbtのプラグイン、assemblyの導入

作戦変更して、jarファイル作成には「assembly」を使用する。

sbt-assemblyはSBTのプラグインで、jarファイルを作る上で依存関係にあるライブラリをまとめるのに便利!


project/assembly.sbtを作成する

addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.14.4")

 

7.実行可能なjarファイルを作成する

sbt assembly

 [エラー4  実行中にエラー  java.lang.RuntimeException: deduplicate: different file contents found in the following]
  ⇒対処法:build.sbtにMerge Strategyを追加する。


build.sbt(最終版)の以下の通りに修正

// ↓以下2行、初回にsbt assemblyするときにコメントアウト外して実行してください
import AssemblyKeys._ // put this at the top of the file
assemblySettings

lazy val root = (project in file(".")).
  settings(
    name := "sample"
    , version := "0.01"
    , scalaVersion := "2.11.8"
  )

  libraryDependencies ++= Seq(
    "org.apache.spark" % "spark-core_2.11" % "2.1.0"
    ,"org.apache.spark" % "spark-sql_2.11" % "2.1.0"
    ,"org.apache.spark" % "spark-mllib_2.11" % "2.1.0"
    ,"org.apache.spark" % "spark-graphx_2.11" % "2.1.0"
    ,"com.datastax.spark" % "spark-cassandra-connector_2.11" % "2.0.0-M3"
  )

  resolvers ++= Seq(
    "Sonatype Snapshots" at "https://oss.sonatype.org/content/repositories/snapshots/"
    ,"Sonatype Releases" at "https://oss.sonatype.org/content/repositories/releases/"
  )

assemblyMergeStrategy in assembly := {
  case PathList("javax", "servlet", xs @ _*)         => MergeStrategy.first
  case PathList(ps @ _*) if ps.last endsWith ".properties" => MergeStrategy.first
  case PathList(ps @ _*) if ps.last endsWith ".xml" => MergeStrategy.first
  case PathList(ps @ _*) if ps.last endsWith ".types" => MergeStrategy.first
  case PathList(ps @ _*) if ps.last endsWith ".class" => MergeStrategy.first
  case "application.conf"                            => MergeStrategy.concat
  case "unwanted.txt"                                => MergeStrategy.discard
  case x =>
    val oldStrategy = (assemblyMergeStrategy in assembly).value
    oldStrategy(x)
}

 

8.再度実行可能なjarファイルを作成する

sbt assembly

  ⇒成功!!

sbt clean package assembly

 

9.jarから実行

/usr/local/lib/spark/bin/spark-submit --class sample.InsertYmd  --master local[4]  <jarファイルのパス>

  ⇒正常に実行!!!

./bin/spark-submit \
  --class <main-class>
  --master <master-url> \
  --deploy-mode <deploy-mode> \
  --conf <key>=<value> \
  ... # other options
  <application-jar> \
  [application-arguments(パラメータの設定)]

 



投稿日:2018-10-04    更新日:2019-02-18

[スポンサーリンク]

サイト内検索
プロフィール

プロフィール

[Name : じゃぶじゃぶ(@jbjb_2019)]
都内で社内SEをしているおじさん。
仕事で得られる知識だけでは限界を感じ、 WEBの勉強がてらITブログを開始。
サーバからWEBサイトまでフルスクラッチで開発しました。
現在は勉強のモチベーションを保つために活用中。
興味があることを雑記的に書いていきます。

[スポンサーリンク]

[スポンサードリンク]

最近の記事