windowsでspark(scala+python)+jupyter環境構築  

# はじめに
機械学習/ディープラーニングの検証環境一式をWindowsで構成してみた。
理由は自宅で触れる最速環境が、GPUも搭載しているWindowsゲーム機だったため。

先人記事のトレースでほぼ導入できたものの、toree周りで問題が発生したため、記録も兼ねて記事とした。
回避策であり、解決策ではありません。参考程度で参照ください。


# 導入コンポーネント

導入したコンポーネントと、参照させていただいた先人皆様の各記事を感謝/敬意をこめてリンクさせていただく。

- [anaconda](https://qiita.com/t2y/items/2a3eb58103e85d8064b6 "@t2yさん")
 - python
 - jupyter
- [apache spark](https://qiita.com/tomotagwork/items/1431f692387242f4a636 "@tomotagworkさん")[^apache spark]
- [toree](https://qiita.com/rockhopper/items/9070fd8b15a738888ec6 "@rockhopperさん")

[^apache spark]: SBT導入までは必須でない
 
 
# Windows固有対応
 
## 各種環境変数
あまりにもメジャーなことで固有とはおこがましいが一応記載
サンプルは下記

```
set JAVA_HOME=C:\program files\Java\xxx
set HADOOP_HOME=D:\programs\spark-2.2.1-bin-hadoop2.7
set SPARK_HOME=D:\programs\spark-2.2.1-bin-hadoop2.7
set PYTHONPATH=%PY4J%;%SPARK_HOME%\python
set PYSPARK_SUBMIT_ARGS="pyspark-shell"
```

 
参考までにpyspark関連をセットするバッチ(これでjupyterからpysparkが使える)

```
@echo off

set TARGET_DIR=%SPARK_HOME%\python\lib

set KEYWORD=py4j-*-src.zip

for /F "usebackq" %%i in (`powershell "(get-childitem '%TARGET_DIR%' | where-Object { $_.Name -like '%KEYWORD%' } | sort-object LastWriteTime | Select-Object -last 1).Name"`) do set LATEST=%%i

set PY4J=%TARGET_DIR%\%LATEST%

set PYTHONPATH=%PY4J%;%SPARK_HOME%\python;%PYTHONPATH%
set PYSPARK_SUBMIT_ARGS="pyspark-shell"
```

 
当たり前ですが、anaconda promptで上記環境変数をセットしてからjupyter notebook起動の順序で。
 
 
## toree公式パッケージのWindows非対応
試してみて初めて知ったのだが、根本的な問題を抱えていた。
ひとまず回避できたので、最短手順を最初に記載する。
 
### pipのアップグレード

toreeアップグレードの前提

```
conda install pip
```

### toreeのアップグレード(0.1.0→0.2.0)

spark-submit実行時NosuckMethodError回避

```
pip install --upgrade https://dist.apache.org/repos/dist/dev/incubator/toree/0.2.0-incubating-rc2/toree-pip/toree-0.2.0.tar.gz
jupyter toree install --spark_home=%SPARK_HOME%
```

　

### toreeシェルのWindowsバッチ化

spark-submit実行失敗の回避

- run.batの配置([入手先](https://issues.apache.org/jira/browse/TOREE-399))
- kernel.jsonの修正

```
C:\ProgramData\jupyter\kernels\apache_toree_scala>diff kernel.json kernel.json.org
3c3
<     "C:\\ProgramData\\jupyter\\kernels\\apache_toree_scala\\bin\\run.bat",
---
>     "C:\\ProgramData\\jupyter\\kernels\\apache_toree_scala\\bin\\run.sh",

C:\ProgramData\jupyter\kernels\apache_toree_scala>
```

　
　

下記は試行錯誤の思い出

---

- toree kernel実行時のエラー→シェルインタープリター(busybox)を入れてラップ(kernel.json修正)

```
[E 13:59:08.740 NotebookApp] Failed to run command:
    ['C:\\ProgramData\\jupyter\\kernels\\apache_toree_scala\\bin\\run.sh', '--profile', 'C:\\Users\\xxxx\\AppData\\Roaming\\jupyter\\runtime\\kernel-c2f63e0d-506a-4ed3-a4ee-a674fd112c19.json']
(略)
    OSError: [WinError 193] %1 は有効な Win32 アプリケーションではありません。
```

- spark-submit実行jarクラスロード時のIOException→run.sh内でネィティブパスからURLに変換して引き渡すようにした

```
Exception in thread "main" java.io.IOException: No FileSystem for scheme: C
```

- spark-submit時のNosuckMethodError→sparkとtoreeのscalaコンパイルバージョン差異が原因。toree0.2.0にアップグレード([参考](https://issues.apache.org/jira/browse/TOREE-354))

```
Exception in thread "main" java.lang.NoSuchMethodError: scala.collection.immutable.HashSet$.empty()Lscala/collection/immutable/HashSet;
        at akka.actor.ActorCell$.<init>(ActorCell.scala:336)
        at akka.actor.ActorCell$.<clinit>(ActorCell.scala)
        at akka.actor.RootActorPath.$div(ActorPath.scala:185)
(略)
```

- toree0.2.0アップグレード時のエラー→pipのアップグレード([参考](https://stackoverflow.com/questions/46499808/pip-throws-typeerror-parse-got-an-unexpected-keyword-argument-transport-enco
))

```
pip install --upgrade https://dist.apache.org/repos/dist/dev/incubator/toree/0.2.0-incubating-rc2/toree-pip/toree-0.2.0.tar.gz
(略)
TypeError: parse() got an unexpected keyword argument 'transport_encoding'
```

- spark-submit時のZMQException→調査/対応断念

```
17/12/27 15:08:13 ERROR ZeroMQSocketRunnable: Unexpected exception in 0mq socket runnable!
org.zeromq.ZMQException: Errno 48 : Address already in use
        at org.zeromq.ZMQ$Socket.mayRaise(ZMQ.java:1425)
        at org.zeromq.ZMQ$Socket.bind(ZMQ.java:1187)
        at org.zeromq.ZMQ$Socket.bind(ZMQ.java:1148)
        at org.apache.toree.communication.socket.ZeroMQSocketRunnable$$anonfun$processOptions$2.apply(ZeroMQSocketRunnable.scala:88)
        at org.apache.toree.communication.socket.ZeroMQSocketRunnable$$anonfun$processOptions$2.apply(ZeroMQSocketRunnable.scala:87)
        at scala.collection.IndexedSeqOptimized$class.foreach(IndexedSeqOptimized.scala:33)
        at scala.collection.mutable.WrappedArray.foreach(WrappedArray.scala:35)
        at org.apache.toree.communication.socket.ZeroMQSocketRunnable.processOptions(ZeroMQSocketRunnable.scala:87)
        at org.apache.toree.communication.socket.ZeroMQSocketRunnable.run(ZeroMQSocketRunnable.scala:144)
        at java.lang.Thread.run(Unknown Source)
```