Pyspark+Docker を用いてPostgreSQLに接続する方法


##背景
Pysparkをローカルで構築するのは少々面倒であったので、Docker imageを利用
Pysparkを用いて社内のDB(Amazon RDS for PostgreSQL)に接続する際にはJDBC Driverを認識させる必要がある
docker,pyspark,postgreSQLの計3つが1つにまとまっている情報がネット上に無かったので、まとめる！！

##仕様

###OS
MacOS Catalina version:10.15.7

###Docker

Jupyterから提供されている「jupyter/pyspark-notebook」を利用

https://hub.docker.com/r/jupyter/pyspark-notebook

###Pyspark/Hadoop version

spark_version = 3.1.2
hadoop_version = 3.2

※Gtihub Dockerfileで確認
https://github.com/jupyter/docker-stacks/blob/master/pyspark-notebook/Dockerfile

###PostgreSQL
社内DBは PostgreSQLを利用
PostgreSQL = 11.6

##手順+ソースコード
###1.PostgreのJBDCドライバーをInstall

以下のサイトからJDBC Driverをダウンロード

https://jdbc.postgresql.org/download.html

今回は「PostgreSQL JDBC 42.2.23」を利用

###2.JDBCドライバーを適当な場所に配置

今回はGUIベースで適当にDesktop配下に配置

###3.ターミナル立ち上げ

ターミナルを起動

###3.Docker imageの作成

```bash
docker image docker pull jupyter/pyspark-notebook
```

###4.Dokcer imageの有無確認
####GUIベースでの確認方法
①：Dockerアプリケーションを起動

②：Containers/Appsをクリック

③：以下の画面ように「Pyspark」のコンテナがあることを確認する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1064902/1daa57fb-daef-788f-ec59-e7c335bf7bcd.png)


####CUIベースでの確認方法
1.ターミナルを起動

2.以下のコマンドで実行

```bash
docker ps -a
```
3.以下の画面ように「Pyspark」のコンテナがあることを確認する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1064902/285bc4b0-ee19-df8b-d07e-b0b4904dd64d.png)

###6.コンテナを起動
####GUIベースでの起動方法

起動したいコンテナにカーソルを合わせると、「START」ボダンが出現するので、「START」ボダンをクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1064902/7742e0b2-4434-8941-49bd-bda4e95c6dc4.png)

####CUIベースでの起動方法(推奨)
以下どちらかのコマンドをターミナル上で実行

```bash
docker run \ 
-e GRANT_SUDO=yes \
--name pyspark　\ 
-it　\ 
-p 8888:8888 \
-e JUPYTER_ENABLE_LAB=yes \
--user root \
-v $PWD:/home/jovyan/work jupyter/pyspark-notebook

```

###7.Jupyter環境に入る

####GUIベースのJupyterを入り方

前段で「START」ボタンをクリック後、コンテナを名前をクリックするとログが出力される
その中に「http://~」から始まるURLがあるので、コピーしてブラウザに貼り付けるとJupyter画面に遷移される

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1064902/ea705fc1-14b2-4aae-29e1-dad52ff8d7c8.png)


####CUIベースのJupyterを入り方

前段の「docker run」以降を実行したあとに、ログが出力される
その中に「http://~」から始まるURLがあるので、コピーしてブラウザに貼り付けるとJupyter画面に遷移される

※注意
Jupyter環境に移行する際にトークンが求められる
「/lab」のあとに「token=~~~」と出ているので、コピペして環境に入ることが可能

###8.Jupyter上での操作

####1.ファイル作成
任意の場所に.ipynbファイルを作成
※作成したファイル上で実行する

####2.JDBCドライバーファイルをdocker pysparkに移動
####①：現在の配下を確認

```python
%pwd
```

####②：ダウンロードしたドライバーの配下まで移動

```python

%cd ~
%cd '/home/jovyan/work/Desktop'

```
####③：コピーコマンドを利用して、ドライバーを「spark-3.1.2-bin-hadoop3.2/jars」配下に格納

```python
!sudo cp postgresql-42.2.23.jar '/usr/local/spark-3.1.2-bin-hadoop3.2/jars/'
```

####④:接続が出来るのかを確認
```python
#必要なライブラリをインポート
import pyspark
from pyspark.sql import SparkSession
from pyspark.sql.functions import *

##sparkインスタンスを立ち上げる
##configでjarsを設定
spark = SparkSession \
  .builder \
  .appName("test") \
  .config("spark.jars", "postgresql-42.2.23.jar") \
  .getOrCreate()
print(spark)

##接続を行いデータフレームに格納
##尚 "****"の箇所である URL/user/DB.table(schema.table)は自身の情報を入力
df = spark.read \
  .format("jdbc") \
  .option("url", "jdbc:postgresql://URL:port番号/DB名") \
  .option("user", "*****") \
  .option("dbtable", "****.****") \
  .option("password", "*****") \
  .option("driver", "org.postgresql.Driver") \
  .load()

###変数の呼び出し及び出力確認
##スキーマを確認
df.printSchema()
##先頭20行を出力
df.show(20)
```

###振り返り・今後について

環境構築にかなりの時間を要してしまった..
docker,pyspark,postgresql計3つを網羅しているネット上には内容はほとんど無かったが、
無事に接続出来てとりあえずは良し！笑

pysparkの既存イメージを利用したが、JDBCdriverが入っていないということもあり、
今後は自身でdockerfileを作ってカスタマイズすれば良いのかも知れない

DB接続は問題無く出来たが、データの加工・集計を行う上で、エラー躓きそうになった部分もあったので、今後機会があればまとめていきたい
ex)メモリエラーや出力の上限エラー等

###参考
・**公式リファレンス**
https://spark.apache.org/docs/latest/api/python/reference/pyspark.sql.html

・**Spark SQL ガイド**
http://mogile.web.fc2.com/spark/sql-data-sources-jdbc.html

・**Using PySpark to connect to PostgreSQL locally**
https://mmuratarat.github.io/2020-06-18/pyspark-postgresql-locally