JupyterでScala

本記事はJupyter 上で Scala で書いたアプリを動かすようにすることを目的としています。

# なぜ、Scala？
Jupyter を使うなら、Python で良いじゃないか！と思われる方も多いかと思います。
しかし、すでにある Scala で書かれた資産（コード）があって、
そのアプリに追加することを前提にした何らかのコードを書きたいとか、
Scala が好きなんだ！とか、
Scala を始めてみたいとか、
人生色々、~~会社~~理由も色々あると思います。
（まぁ、単純に筆者が Scala が好きで、Spark-Shell辛いけど、わざわざ、pyspark のAPIを覚えるの面倒だからという理由だったります。）

# 環境
以下の環境が事前に整っている前提です。

## 必須
### Python
3系

### sbt
1.0.3
(試してはいませんが、0.13系でも大丈夫じゃないかと)

### Scala
2.12.2
(何で2.12系にしたのやら・・・2.11系で動くはずです)

### Jupyter Scala
0.4.2(2017/11/14 時点での最新)

### Jupyter kernel
0.4.1(2017/11/14 時点での最新)

### Java
OpenJDK 8
(Java 8なら、Oracle JDK8 でも良いはず。今回はAmazon EMRに近付けたいため、EMRデフォルトのOpen JDKをyum installしています)

## 任意
### OS
Amazon Linux 2017.03 の Docker image 
(別に Python と JVMM が動くなら何でも良いです。Windows の場合は適宜、パスやコマンドをWindows のものに読み替えてください)

### Spark
2.2.0
※ Jupyter 上で Scala を動かすだけであれば不要です。Spark アプリを動かすために構築した際の手順のため、Spark を動かすための設定を行っていたりします。

### Docker周り
Jupyter 上で Scala を動かすだけであれば不要です。
今回は Amazon EMR に近い環境としたかったため、docker-compose を使って、
Spark クラスターを構築し、master ノード上で Jupyter を建てて、ホストからアクセスするようにしています。

 - Docker CE 17.09.0 (多分、docker-ceならどのバージョンでも大丈夫かと)
 - docker-compose


# 構築手順

## Jupyter をインストールする

JupyterLab とかはお好みでと言ったところでしょうか
Spark を使わなければ、jupyter, notebook(or jupyterlab), py4j あたりがあれば良いのかお知れません(py4jも必須かは怪しいかも)

```bash
pip install jupyter
pip install notebook
pip install jupyterlab
pip --no-cache-dir install pandas pyspark
pip install py4j jupyter-spark lxml
pip install --upgrade beautifulsoup4 html5lib
jupyter nbextension install --py jupyter_spark
jupyter serverextension enable --py jupyter_spark
jupyter nbextension enable --py jupyter_spark
jupyter nbextension enable --py widgetsnbextension
jupyter serverextension enable --py jupyterlab --sys-prefix

pip install scipy scikit-learn pygments && \
pip3 install scipy scikit-learn pygments pandas pyspark ipykernel ipython
```

## sbt をインストールする

今回のは、Dockerfile で Docker Image を構築しているため、`sudo` なり `doas` を行っていませんが、必要に応じて適宜、`sudo` なり `doas` を行なってください。

```bash
##
# Dockerfile では
# ENV SBT_HOME /usr/local/sbt
# ENV PATH ${PATH}:${SBT_HOME}/bin
# と記述
##

echo "export SBT_HOME=/usr/local/sbt" >> .bashrc
echo "export PATH=${PATH}:${SBT_HOME}/bin" >> .bashrc


export SBT_VERSION=1.0.3
curl -sL "https://github.com/sbt/sbt/releases/download/v${SBT_VERSION}/sbt-${SBT_VERSION}.tgz" | tar -xz -C /usr/local
```

## Jupyter kernel/Jupyter Scala をインストールする

```bash
# Jupyter Scala のインストール
curl -sL "https://github.com/jupyter-scala/jupyter-scala/archive/v0.4.2.tar.gz" | tar -xz -C /usr/local && \
cd /usr/local/ && \
ln -s jupyter-scala-0.4.2 jupyter-scala && \
cd jupyter-scala && \
sbt publishLocal

# Jupyter Kernel のインストール
curl -sL "https://github.com/jupyter-scala/jupyter-kernel/archive/v0.4.1.tar.gz" | tar -xz -C /usr/local &&\
cd /usr/local/ && \
ln -s jupyter-kernel-0.4.1 jupyter-kernel && \
cd jupyter-kernel && \
sbt publishLocal

# 仕上げ
# Windows の場合は https://github.com/jupyter-scala/jupyter-scala/blob/master/jupyter-scala.ps1 を使えば良さそう

# /root 配下じゃ無くても良さそう
curl -sL "https://raw.githubusercontent.com/alexarchambault/jupyter-scala/master/jupyter-scala" -o /root/jupyter-scala.sh && \
chmod 744 /root/jupyter-scala.sh && \
sed -e "s/2.11.11/2.12.4/gi" /root/jupyter-scala.sh && \
/root/jupyter-scala.sh && \
rm -f /root/jupyter-scala.sh
```

これで Jupyter を起動すると以下のように、Jupyter 上で Scala が使えるようになります。
※ JupyterLab の起動画面
![スクリーンショット 2017-11-15 22.46.48.png](https://qiita-image-store.s3.amazonaws.com/0/6762/cfe20af8-f3be-14b8-349f-426d278df7a4.png)

# 動かしてみる
それぞれのセルに、以下のようなコードを記述してみました。

```Scala
import $ivy.`org.apache.spark::spark-sql:2.2.0`
import $ivy.`org.apache.hadoop:hadoop-aws:2.7.3`
import $ivy.`org.jupyter-scala::spark:0.4.2`
```

```Scala
import org.apache.spark.sql.SparkSession
import org.apache.spark.{SparkConf, SparkContext}
```

```Scala
//Configuration
import jupyter.spark.session._

val spark = JupyterSparkSession
  .builder() // important - call this rather than SparkSession.builder()
  .jupyter()
  .master("local[*]")
  .config("spark.driver.memory","2g")
  .config("spark.memory.useLegacyMode", "true")
  .appName("notebook")
  .getOrCreate()
```
```Scala
spark
  .sparkContext
  .parallelize(Array("Hello", "World", "!"))
  .foreach(System.err.println)
```
```Scala
spark.stop()
```

![スクリーンショット 2017-11-17 0.42.31.png](https://qiita-image-store.s3.amazonaws.com/0/6762/c81370a6-4eab-a16f-3abd-d8c23ce6e161.png)


## 依存ライブラリの参照
以下のように記述する

```
$ivy.`group::artifact:version`
``` 

参考：https://github.com/jupyter-scala/jupyter-scala#spark

# まとめ
sbt と Jupyter kernel/Jupyter Scala をインストールすればよい。

# 余談
職場などで、proxy を通す場合
https://github.com/jupyter-scala/jupyter-scala/issues/21
のとおり実施したら動作せず。

以下のように、argv セクションに追加したら動作しました

```$json
{
  "language" : "scala",
  "display_name" : "Scala",
  "argv" : [
    "java",
    "-noverify",
    "-Dhttp.proxyHost=...",
    "-Dhttp.proxyPort=...",
    "-Dhttps.proxyHost=...",
    "-Dhttps.proxyPort=...",
    "-jar",
    "/root/.local/share/jupyter/kernels/scala/launcher.jar",
    "launch",
    "-r",
    "sonatype:releases",
    "-r",
    "sonatype:snapshots",
    "-i",
    "ammonite",
    "-I",
    "ammonite:org.jupyter-scala:ammonite-runtime_2.11.11:0.8.3-1",
    "-I",
    "ammonite:org.jupyter-scala:scala-api_2.11.11:0.4.2",
    "org.jupyter-scala:scala-cli_2.11.11:0.4.2",
    "--",
    "--id",
    "scala",
    "--name",
    "Scala",
    "--quiet",
    "--connection-file",
    "{connection_file}"
  ]
}

```