初心者がPysparkをJupyter notebookで動かすのに6時間かかった話


## はじめに
WindowsでSpark(Pyspark)の環境構築を行った際に、エラーの解決方法がわからずハマってしまったので、備忘録として共有したいと思います。もし間違っている箇所などあればご指摘いただけると幸いです。

##当初参考にしたサイト
- [How to Install and Run PySpark in Jupyter Notebook on Windows](https://changhsinlee.com/install-pyspark-windows-jupyter/)
- [上記サイトの手順の解説動画](https://www.youtube.com/watch?v=Rv4NOAn2m-g&list=WL&index=1)

##ハマったエラー内容
上記サイトおよびYoutube動画を参考にインストールし、下記コードをJupyter notebookで実行したところエラーとなりました。

#####コード
```
import findspark
findspark.init()

import pyspark # only run after findspark.init()
from pyspark.sql import SparkSession

spark = SparkSession.builder.getOrCreate()

df = spark.sql('''select 'spark' as hello ''')
df.show()
```

#####エラー文
```
Exception: Java gateway process exited before sending the driver its port number
```

このエラー文でググったところ[stackoverflow](https://stackoverflow.com/questions/31841509/pyspark-exception-java-gateway-process-exited-before-sending-the-driver-its-po)のスレッドも見つかりましたが、色々な可能性が示唆されていて正直何のこっちゃという感じでした。これらをもとに四苦八苦しながら6時間くらいかかって解決したので、やったこと（かつ効果があったと思われるもの）を以下列挙します。最終的には、Javaのバージョン変更が効きました

##試したこと

#####JavaとSparkのフォルダ位置の変更
JavaはデフォルトだとProgram Filesの下にインストールされると思います。[このコメント](http://disq.us/p/1z5qou4)にもあるように、フォルダ名にスペースがあるとうまくいかないらしく、Cドライブの直下に移動しました(C:\Java)。

同様に、SparkもCドライブ直下に置きました。

#####環境変数の変更
[当初参考にしたサイト](https://changhsinlee.com/install-pyspark-windows-jupyter/)のB5にあったように、JAVA_HOMEという環境変数をC:\Javaとして追加しました（パスはご自身の環境に合わせて変えてください。私の場合はCドライブの直下にJavaを入れていたためC:\Javaになっています）。

#####Sparkとwinutils.exeのバージョン変更
Apache Sparkをインストールする際に何も考えずにデフォルトのバージョンを選択していたのですが、デフォルトだと下記画像のようにHadoopのバージョンは3.2になっていました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634758/c3848b4c-b5e7-7337-69fc-d0b6bcb7c8de.png)
しかし、[Hadoop binaryの配布サイト](https://github.com/steveloughran/winutils/)では、3.2のバージョンは2021/07現在存在しません。なので、Sparkのバージョンを"Pre-built for Apache Hadoop 2.7"で再インストールし、winutils.exeも2.7.1のものをダウンロードしてSparkのbin直下に置きなおしました。
（＊こちらはHadoopの話のため当初のコードを動かすのには関係ないかもしれませんが、後々悪影響があるかもしれないので行っておきました）

#####Pythonのバージョン変更
Pythonのバージョンは3.8だったのですが、[Sparkの公式ドキュメント](https://spark.apache.org/docs/latest/)を見ると、"_Spark runs on Java 8/11, Scala 2.12, Python 3.6+ and R 3.5+_"とあります。
こちらが原因かはわかりませんが、念のため古いバージョンのPythonを再インストールしました。Anacondaでのバージョン対応表については[こちら](https://qiita.com/sho1_24/items/306ff5d30b230b36de3a)を参考にしました。

#####Javaのバージョン変更
[stackoverflow](https://stackoverflow.com/questions/31841509/pyspark-exception-java-gateway-process-exited-before-sending-the-driver-its-po)でもJavaのバージョンが問題だったという書き込みが複数ありました。
Java 16を元々はダウンロードしていたのですが、[Oracleのサイト](https://www.oracle.com/java/technologies/javase-downloads.html)からJava 8を再ダウンロードしました（アカウント作成を求められるかもしれません）。

##結果
Javaのバージョン変更を行った後にJupyter notebook上で元々のコードを実行すると、、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634758/68241dce-6c96-c10a-7b74-a5fa65297db1.png)

なんとか動いてくれました！

--------------------
以上、私のようにWindowsでJupyter notebook上でPyspark動かしたいけどハマっている方に参考になれば幸いです。


##追記

翌日同じように動かそうとすると下記エラーにぶち当たりました（なぜ前日上手くいっていたのかよくわからないですが、、）。

```
py4j.protocol.Py4JError: org.apache.spark.api.python.PythonUtils.getEncryptionEnabled does not exist in the JVM
```

エラー文で色々とググったところ、Stackoverflowの[この記事](https://stackoverflow.com/questions/53161939/pyspark-error-does-not-exist-in-the-jvm-error-when-initializing-sparkcontext)を見つけました。要するに、PysparkとSparkのバージョンを一緒にしないといけないということですね。Anaconda Powershellで

```
pip freeze
```
で調べてみるとPysparkのバージョンは3.1.2でした。以前ダウンロードしたSparkは3.0.3だったので、改めて3.1.2のSparkを再ダウンロードしたところきちんと動くようになりました。