re:dashからAmazon Athenaにクエリを投げる

2016/12/01に、Amazon S3上のデータにアドホックにSQLクエリを投げられるサービスである**Amazon Athena**がリリースされました。
Athenaの概要に関しては以下をどうぞ。

[Amazon Athena – Amazon S3上のデータに対話的にSQLクエリを](https://aws.amazon.com/jp/blogs/news/amazon-athena-interactive-sql-queries-for-data-in-amazon-s3/)
[Amazon Athenaを使ってみました #reinvent](http://dev.classmethod.jp/cloud/aws/try-aws-athena/)
[Amazon AthenaをBigQueryと比較してみた](http://data.gunosy.io/entry/aws-athena-vs-bigquery)

自分で軽く使ってみた感じだと、SaaSなので管理コストが低い上にクエリのパフォーマンスもかなり良く、**非常に可能性を感じるサービス**だという印象です。

というわけでAmazon Athenaをもっと使っていきたいので、OSSのBIツールである**re:dash**からAmazon Athenaにクエリを投げられるようにしました。皆さんも良かったらやってみてください。

**コメント欄にもありますが、re:dash作者の@arikfrさんが既に公式でのAthenaサポートを作成中だそうです！リリースされましたらそちらを使った方が楽ですね。**

##環境
* Ubuntu14.04
* Python 2.7.6

##作業手順

###py4jのインストール
Athenaは現状ではJDBC経由の接続しかサポートしていないので、pythonから接続するには一手間いります。

今回はPythonからjarを実行するために、別プロセスで起動しているjavaとソケット通信経由で連携する**py4j**を使う事にしました。pipでインストールできます。

```sh
$ sudo pip install py4j
```

###Java8のインストール
Athenaとの接続を行うためには**Java8以上が必須**です。

[Ubuntu 14.04にOpen JDK 8を導入する](http://note.kurodigi.com/ubuntu1404-openjava8)

```sh
$ sudo apt-add-repository ppa:openjdk-r/ppa
$ sudo apt-get update
$ sudo apt-get install openjdk-8-jdk
$ java -version
openjdk version "1.8.0_111"
OpenJDK Runtime Environment (build 1.8.0_111-8u111-b14-3~14.04.1-b14)
OpenJDK 64-Bit Server VM (build 25.111-b14, mixed mode)
```

また、自分はSSL関係でつまづき以下のコマンドも実行しました。

```sh
$ sudo dpkg --purge --force-depends ca-certificates-java
$ sudo apt-get install ca-certificates-java
$ sudo /var/lib/dpkg/info/ca-certificates-java.postinst configure
```

###Javaサーバプログラムの作成
Athenaとのコネクションを確立するためのJavaのサーバー用クラスを作成します。以下の記事を参考にさせていただきました。

[CPythonからJavaのクラスを呼び出す(Py4J)](http://qiita.com/mojaie/items/f16b97b1388f73e56b86)
[Accessing Amazon Athena with JDBC](http://docs.aws.amazon.com/athena/latest/ug/connect-with-jdbc.html)


```java:J4Py.java

public class J4Py {
  public static void main(String[] args) {
    J4Py app = new J4Py();
    GatewayServer server = new GatewayServer(app);
    server.start();
  }
}
```

```java:AthenaJDBCConnector.java

public class AthenaJDBCConnector {

	Properties info;
	String url;

	public AthenaJDBCConnector(Properties info, String url) {
		this.info = info;
		this.url = url;
	}

	public Connection getConnection() {		
		try {
			Class.forName("com.amazonaws.athena.jdbc.AthenaDriver");
			Connection conn = DriverManager.getConnection(this.url, this.info);
			return conn;
		} catch (Exception ex) {
			ex.printStackTrace();	
		}

		return null;
	}

}
```

###Jarファイル作成
先ほどのプログラムからJarファイルを作成します。

`AthenaJDBC41-1.0.0.jar`は公式からダウンロードできます。

```sh
$ javac -cp AthenaJDBC41-1.0.0.jar AthenaJDBCConnector.java
$ jar cvf AthenaJDBCConnector.jar AthenaJDBCConnector.class
```

`py4j0.10.4.jar`はpy4jインストール時に付いてきます。

```manifest.fm
Main-Class: J4Py
Class-Path: py4j0.10.4.jar AthenaJDBC41-1.0.0.jar
```

```sh
$ javac -cp py4j0.10.4.jar:AthenaJDBCConnector.jar:AthenaJDBC41-1.0.0.jar J4Py.java
$ jar cvfm J4Py.jar manifest.mf J4Py.class
```

`J4Py.jar`の作成が終了しました。サブプロセスで`J4Py.jar`を立ち上げれば以下のようにしてpythonからAthenaのクエリが投げられます。

```sh
$ java -jar J4Py.jar
```

```python:test_connection.py
from py4j.java_gateway import JavaGateway

gateway = JavaGateway()
info = gateway.jvm.java.util.Properties()
info.setProperty("s3_staging_dir", 'xxx')
info.setProperty("user", 'yyy')
info.setProperty("password", 'zzz')
host = 'jdbc:awsathena://athena.us-west-2.amazonaws.com:443/'
connector = gateway.jvm.AthenaJDBCConnector(info, host)
conn = connector.getConnection()
statement = conn.createStatement()
rs = statement.executeQuery(query)
```

###re:dashへのデータソース追加
re:dashは**データソースをプラガブルに追加可能**です。先ほどのpythonファイルの要領でBaseQueryRunnerを継承したクラスを作成します。少し長くなったので外部に置きます。

[athena.py](https://github.com/kakakazuma/redash/blob/0d47c900f7ac86f0769faeb5769fc9e781948d6e/redash/query_runner/athena.py
)

作成したクラスをquery_runner/直下に追加し、以下のように`/opt/redash/.env`に追記してre:dashを再起動すればOKです。事前に`J4Py.jar`プロセスを立ち上げるのを忘れないようにしてください。(re:dashはsupervisordで管理されているので、そこに相乗りさせると良いかもしれません)

```
export REDASH_ADDITIONAL_QUERY_RUNNERS=redash.query_runner.athena
```

###クエリ実行
データソースを追加したら画面上から設定が行えるようになりますので、必要な項目を入力してクエリを投げてみます。

####項目の入力
<img width="822" alt="スクリーンショット 2016-12-09 17.28.27.png" src="https://qiita-image-store.s3.amazonaws.com/0/49019/48aeb7a9-8f5c-5aca-43df-f7255a0fb4e1.png">

####クエリ実行
<img width="1336" alt="スクリーンショット 2016-12-09 17.29.38.png" src="https://qiita-image-store.s3.amazonaws.com/0/49019/53d8efab-f29b-e3e0-31cc-89812302051a.png">


無事にクエリが投げられました！

##終わり
re:dashとAthenaを使えば低コストで簡単にデータの可視化が行えますので、是非試してみてください！

今回のソースは
https://github.com/kakakazuma/redash/tree/feature/athena
にコミットしてあります。

~~Athenaの需要はあると思うのでプルリクを出したいのですが、Java8が必須だったり別プロセスでJavaを走らせる必要があったりと少し複雑になってしまうので、フォーラムで相談してみます。~~
**公式で既に作成中のようなので、問題なさそうです！**