EMR5.7でAmazonDynamoDBClientBuilderが上手く使えない対応

# 環境

EMRは5.7。
aws-java-sdk-dynamodbのバージョンは下記。

```scala:build.sbt
libraryDependencies += "com.amazonaws" % "aws-java-sdk-dynamodb" % "1.11.170"
```

`sbt assembly` で固めたFAT-JARをEMR上にデプロイ＆実行するとエラーが発生。
ローカルでは上手く動くので原因がわからず少し困った。


# 事象
EMR5.7にて `AmazonDynamoDBClientBuilder` を利用すると `NoClassDefFoundError`。
`AmazonDynamoDBClientBuilder` はパスを通している（FAT-JARに含まれている）ので、`ClassNotFoundException` では無いだろうと思っていたが、原因が特定できず戸惑った。

```:エラー1
17/08/14 10:17:39 INFO Client:
　　　　(略)
java.lang.NoClassDefFoundError: Could not initialize class com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder
        at SparkApp$$anonfun$main$1$$anonfun$1.apply(SparkApp.scala:58)
        at SparkApp$$anonfun$main$1$$anonfun$1.apply(SparkApp.scala:51)
        at org.apache.spark.rdd.RDD$$anonfun$mapPartitions$1$$anonfun$apply$23.apply(RDD.scala:797)
        at org.apache.spark.rdd.RDD$$anonfun$mapPartitions$1$$anonfun$apply$23.apply(RDD.scala:797)
        at org.apache.spark.rdd.MapPartitionsRDD.compute(MapPartitionsRDD.scala:38)
        at org.apache.spark.rdd.RDD.computeOrReadCheckpoint(RDD.scala:323)
        at org.apache.spark.rdd.RDD.iterator(RDD.scala:287)
        (略)
```

しばらく動かしたりログを探すと、IllegalAccessErrorがでていた。
どうやらこれが原因なようだ。

```:エラー2
17/08/14 11:04:29 INFO Client:
　　　　(略)
java.lang.IllegalAccessError: tried to access class com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientConfigurationFactory from class com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder
        at com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder.<clinit>(AmazonDynamoDBClientBuilder.java:27)
        at SparkApp$$anonfun$main$1$$anonfun$1.apply(SparkApp.scala:58)
        at SparkApp$$anonfun$main$1$$anonfun$1.apply(SparkApp.scala:51)
        at org.apache.spark.rdd.RDD$$anonfun$mapPartitions$1$$anonfun$apply$23.apply(RDD.scala:797)
        at org.apache.spark.rdd.RDD$$anonfun$mapPartitions$1$$anonfun$apply$23.apply(RDD.scala:797)
        at org.apache.spark.rdd.MapPartitionsRDD.compute(MapPartitionsRDD.scala:38)
        at org.apache.spark.rdd.RDD.computeOrReadCheckpoint(RDD.scala:323)
        at org.apache.spark.rdd.RDD.iterator(RDD.scala:287)
```

# 調査

調べるといくつか出てきた。

> * https://stackoverflow.com/questions/43237791/illegalaccesserror-when-running-spark-job-in-emr
> * https://stackoverflow.com/questions/45197850/cant-create-dynamodb-client-in-spark-executor
> I was Finally able to solve it by using lower version of DynamoDB API.
> The EMR 5.7 only supports 1.10.75.1. Below is the code that works fine for me.

どうやら、EMR5.7はaws-java-sdkのバージョンが `1.10.75.1` までしか対応していないとのこと。現在（※2017/08/15）は1.11系が出ているので、けっこう古い。というか本当なのか？


ということで、公式のドキュメントを調べると...

> AWS SDK for Java が 1.10.75 にアップグレード
> * http://docs.aws.amazon.com/ja_jp/emr/latest/ReleaseGuide/emr-whatsnew.html

と書いてあり、`1.10.75` までは対応していることは見つけたが、それ以降のバージョンについては述べていない。うーむ、信頼できるのか？

# 対応
ということで、半信半疑ながらSDKのバージョンをダウングレードした。

```scala:build.sbt
libraryDependencies += "com.amazonaws" % "aws-java-sdk-dynamodb" % "1.10.75.1"
```

そうすると、`AmazonDynamoDBClientBuilder`が利用できないので、今ではdeplicatedになっている`AmazonDynamoDBClient`を利用して書き換えすることに。

```scala:OLD_dynamodbサンプル.scala
    val client = AmazonDynamoDBClientBuilder.standard
      .withRegion("ap-northeast-1")
      .build
    val dynamoDB = new DynamoDB(client)
```

こちら↑をすこし編集するのみで動いてくれた。

```scala:NEW_dynamodbサンプル.scala
    val client = new AmazonDynamoDBClient()
    client.setRegion(Region.getRegion(Regions.AP_NORTHEAST_1))
    val dynamoDB = new DynamoDB(client)
```

# 実行結果

実行すると...
上手く動いてくれた。さすがStackOverFlow！

なぜ `IllegalAccessError` が出てしまうかだが、EMR上でもaws-java-sdkがロードされていると思うので、かみ合わせが悪いのか？このあたりよく分かっていない。


# まとめ

EMRでDynamoDBに書き込む時は、SDKのバージョンに気をつけよう。