最近、Hadoop周りの学習を始めて、Sparkをもと思いこちらの書籍を購入。学習環境を構築しました。
こちらの書籍のSparkは1系で、バージョンが古いので都度互換を吸収する必要があります。
コンテナの作成
以下はDockerのプロファイル。殆どQiitaから拾ってきたんだけど、spark-submit
でscalaプログラムを動かすにはscalaのビルド環境が必要になるので、sbtも併せて含めておく。
Dockerfile
FROM openjdk:8 ARG SPARK_VERSION=2.4.6 ARG HADOOP_VERSION=2.7 RUN echo "deb https://dl.bintray.com/sbt/debian /" | tee -a /etc/apt/sources.list.d/sbt.list RUN curl -sL "https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x2EE0EA64E40A89B84B2DF73499E82A75642AC823" | sudo apt-key add RUN apt-get update \ && apt-get install sbt RUN wget -q http://ftp.meisei-u.ac.jp/mirror/apache/dist/spark/spark-${SPARK_VERSION}/spark-${SPARK_VERSION}-bin-hadoop${HADOOP_VERSION}.tgz RUN tar xzf spark-${SPARK_VERSION}-bin-hadoop${HADOOP_VERSION}.tgz \ && mv spark-${SPARK_VERSION}-bin-hadoop${HADOOP_VERSION} /spark \ && rm spark-${SPARK_VERSION}-bin-hadoop${HADOOP_VERSION}.tgz EXPOSE 8080
docker-compose
version: '3' services: master: build: . ports: - 4040:4040 - 8080:8080 volumes: - .:/spark/work command: /spark/bin/spark-class org.apache.spark.deploy.master.Master --host 0.0.0.0 worker: build: . depends_on: - master ports: - 8081-8089:8081 command: /spark/bin/spark-class org.apache.spark.deploy.worker.Worker spark://master:7077 --host 0.0.0.0
コンテナの起動
$ docker-compose up -d
上記で、docker exec -it containerID bash
なんかして、/spark/bin/spark-shell
なんかするとインタラクティブシェルでSparkを扱うことができる。
スタンドアロンアプリケーションの構築
インタラクティブシェルでなく、ScalaやJava、Python等のプログラムからSparkを利用ことをスタンドアロンアプリケーションと呼ぶらしい。利用するアプリケーションのコードは GitHub - databricks/learning-spark: Example code from Learning Spark book 書籍のコードが公開されているので、こちらをforkしてDockerにマウントしてあるパスに配置しておいた。
以下はDockerコンテナにログインしておいて作業します。
配置したgithubのコード、mini-complete-example/
というアプリケーションに移動して、書籍通り以下を実行する。
$ sbt clean package $ /spark/bin/spark-submit \ --class com.oreilly.learningsparkexamples.mini.scala.WordCount \ ./target/scala-2.10/learning-spark-mini-example_2.10-0.0.1.jar \ ./README.md ./wordcounts
ビルドは成功するんだけど、以下のようなエラーが出て、ランタイムエラーが出る。
Exception in thread "main" java.lang.NoSuchMethodError: org.apache.spark.SparkContext$.rddToPairRDDFunctions(Lorg/apache/spark/rdd/RDD;Lscala/reflect/ClassTag;Lscala/reflect/ClassTag;Lscala/math/Ordering;)Lorg/apache/spark/rdd/PairRDDFunctions;
これは、ビルドしたScalaのバージョンとランタイム(この場合Sparkが実行するScalaのバージョン)が違う時に現れるエラーのようで、ビルド時のバージョンをSparkのランタイムのバージョンに合わすようにする。
mini-complete-example/build.sbt
を
scalaVersion := "2.11.12"
とする。
再度ビルドすると、今度は
[error] (update) sbt.librarymanagement.ResolveException: Error downloading org.apache.spark:spark-core_2.11:1.1.0
と依存パッケージのバージョンが解決できないので、こちら scala - sbt got error when run Spark hello world code? - Stack Overflow を参考し解決を計った。
mini-complete-example/build.sbt
を変更する
"org.apache.spark" % "spark-core_2.11" % "2.1.0"
これでビルドが通る。と思いきや、
[error] /spark/work/github/mini-complete-example/src/main/java/com/oreilly/learningsparkexamples/mini/java/WordCount.java:34:1: <anonymous com.oreilly.learningsparkexamples.mini.java.WordCount$1> is not abstract and does not override abstract method call(java.lang.String) in org.apache.spark.api.java.function.FlatMapFunction
同梱されているJavaのファイルでエラーがでる(笑)
https://stackoverrun.com/ja/q/10668208 を参考に、該当箇所のコードを、
JavaRDD<String> words = input.flatMap(l -> Arrays.asList(l.split(" ")).iterator());
に変更する。
これでビルドが通る。
spark-submitの実行
再度、
$ sbt clean package $ /spark/bin/spark-submit \ --class com.oreilly.learningsparkexamples.mini.scala.WordCount \ ./target/scala-2.10/learning-spark-mini-example_2.10-0.0.1.jar \ ./README.md ./wordcounts
とすると
WARN DependencyUtils: Local jar /spark/work/github/mini-complete-example/./target/scala-2.10/learning-spark-mini-example_2.10-0.0.1.jar does not exist, skipping.
となる。そうだった、Scalaのバージョンを変更したので、
/spark/bin/spark-submit \ --class com.oreilly.learningsparkexamples.mini.scala.WordCount \ ./target/scala-2.11/learning-spark-mini-example_2.11-0.0.1.jar \ ./README.md ./wordcounts
とビルドしたjarのターゲット先を変更。
これでspark-submit
に指定したwordcounts
ディレクトリにアプリケーションの実行結果が保存されます。