SpringBootを使ってAWS Athenaへ接続してみる
はじめに
DI部のおおたきです。AWS AthenaはJDBCで接続が可能です。そこで今回SpringBootを使ってAWS Athenaに接続してみました。
AWS Athenaとは?って方はこちらを参照ください。
開発環境
今回実装した開発環境です。
- Windows7
- pleiades4.6.3
- java8
開発環境を用意する
pleiades-4.6.3を使って開発しました。(気がつくとどんどんバージョンが上がっている。)
SpringBootを使うのでプラグインとしてSTSをインストールします。
pleiadesを起動してメニューのヘルプ->Eclipseマーケットプレイスを選択して、「STS」で検索します。「Spring Tool Suite」をインストールします。
プロジェクトを作成する
SpringBootのプロジェクトを作成します。
メニューのファイル->新規->その他->Springから「Springスターター・プロジェクト」を選択します。
プロジェクトの設定はこんな感じです。今回はGradleを使用しています。
またSpringBootのバージョンは2.0.0を使ってみました。
Gradleの設定をする
AWS Athenaに接続するにはJDBCドライバとクレデンシャルを利用した認証が必要なのでAWS SDKを使用できるようにします。またSpring-JDBCも使用するのでそちらも合わせて設定をします。build.gradleを修正します。以下ハイライトの部分が追加した箇所になります。
buildscript { ext { springBootVersion = '2.0.0.BUILD-SNAPSHOT' } repositories { mavenCentral() maven { url "https://repo.spring.io/snapshot" } maven { url "https://repo.spring.io/milestone" } } dependencies { classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") } } apply plugin: 'java' apply plugin: 'eclipse' apply plugin: 'org.springframework.boot' apply plugin: 'io.spring.dependency-management' version = '0.0.1-SNAPSHOT' sourceCompatibility = 1.8 repositories { mavenCentral() maven { url "https://repo.spring.io/snapshot" } maven { url "https://repo.spring.io/milestone" } maven { url "https://maven.atlassian.com/repository/public" } } dependencies { compile('org.springframework.boot:spring-boot-starter') compile 'org.springframework.boot:spring-boot-starter-jdbc' compile group: 'com.amazonaws.athena.jdbc', name: 'AthenaJDBC41', version: '1.0.1-atlassian-hosted' compile group: 'com.amazonaws', name: 'aws-java-sdk', version: '1.11.128' testCompile('org.springframework.boot:spring-boot-starter-test') }
設定が完了したらbuild.gradleを選択し、右クリックからGradle->Gradleプロジェクトのリフレッシュを選択します。これで必要なjarファイルがダウンロードされます。
実装する
今回はAthenaにdefault
というデータベースを作成し、customer
というテーブルを事前に作成しておいたのでそのデータを読み込んでみます。customer
テーブルは以下の項目があります。
- id
- code
- status
- create_date
接続情報を設定する
Athenaへの接続情報を設定します。Athenaは通常のDBへのアクセス情報とは別にs3_staging_dir
という設定が必須になります。これは実行したSQLの結果をS3上に出力するための出力先情報になります。通常SpringBootではDBへのアクセス情報はapplication.properties
ファイルに以下のように記載します。
spring.datasource.url=jdbc:mysql://localhost/test spring.datasource.username=dbuser spring.datasource.password=dbpass spring.datasource.driver-class-name=com.mysql.jdbc.Driver
s3_staging_dir
についてもspring.datasource.s3_staging_dir=xxxxxx
と設定すればよさそうですが、残念ながら正しく認識されません。
そのためデータソース情報はカスタムして設定する必要があります。またAthenaではユーザー、パスワード(ユーザーはaws_access_key_id、パスワードはaws_secret_access_keyを指定する)を設定する方法とAWS Credentials Providerを指定する方法があります。今回は後者の設定方法で実装をしてみたいと思います。そのためapplication.properties
にはurlとdriver-classのみを設定します。Athenaはオレゴンリージョンを使っていますのでus-west-2
を指定しています。
spring.datasource.url=jdbc:awsathena://athena.us-west-2.amazonaws.com:443 spring.datasource.driver-class-name=com.amazonaws.athena.jdbc.AthenaDriver
AthenaのJDBCオプションの詳細はこちらを参照下さい。
次にプロジェクト生成時に作成されたSampleAthenaApplication
クラスを開き、データソース情報を実装します。また今回はDBへのアクセス方法はSpringのJdbcTemplateを使用して実装しました。setDataSourceメソッドはSpringBoot実行時に呼び出されます。
@Autowired private JdbcTemplate jdbc; @Autowired public void setDataSource(DataSource dataSource) { PoolConfiguration configuration = ((org.apache.tomcat.jdbc.pool.DataSource)dataSource).getPoolProperties(); Properties properties = configuration.getDbProperties(); properties.put("s3_staging_dir", "s3://cm-sample-bucket/results"); properties.put("log_path", "d://logs/test.log"); properties.put("aws_credentials_provider_class","com.amazonaws.auth.profile.ProfileCredentialsProvider"); properties.put("aws_credentials_provider_arguments","blog"); configuration.setDbProperties(properties); this.jdbc = new JdbcTemplate(dataSource); }
ProfileCredentialsProviderを使用していますので「~/.aws/credentials」に配置した認証情報ファイルを参照します。Windowsの場合だと「C:\Users\<ユーザー名>.aws\credentials」のファイルが参照されます。
aws_credentials_provider_arguments
はプロファイル名を指定します。使用した「credentials」ファイルの中身は以下のようになっています。
[default] aws_access_key_id=xxxxxxxxxxxxxxxxxx aws_secret_access_key=xxxxxxxxxxxxxxxxxx [blog] aws_access_key_id=xxxxxxxxxxxxxxxxxx aws_secret_access_key=xxxxxxxxxxxxxxxxxx
またlog_path
は実行時のログを出力するパスを指定します。
SQLを実装する
AthenaにアクセスするSQLを実装します。実装は単純にSELECTした結果を標準出力させています。
public void run(String... args) throws Exception { List<Map<String, Object>> list = this.jdbc.queryForList("select id,code,status,create_date from default.customer limit 100"); list.forEach(System.out::println); }
SQLを呼び出す
最後にmainメソッドを修正して、runメソッドを呼び出すようにします。
public static void main(String[] args) { ConfigurableApplicationContext ctx = SpringApplication.run(SampleAthenaApplication.class, args); SampleAthenaApplication app = ctx.getBean(SampleAthenaApplication.class); try { app.run(args); } catch (Exception e) { e.printStackTrace(); } }
実行してみる
実行すると以下のようにデータが取得できました。
{id=17893072, code=100, status=20, create_date=20170117124345} {id=17892387, code=100, status=20, create_date=20170117015617} {id=17889502, code=100, status=20, create_date=20170117102933} {id=17892640, code=100, status=20, create_date=20170117105624} {id=17893050, code=100, status=20, create_date=20170117130739} {id=17893801, code=100, status=10, create_date=20170117151554} {id=17895646, code=100, status=20, create_date=20170117213716} {id=17892546, code=100, status=20, create_date=20170117102030} {id=17894320, code=100, status=20, create_date=20170117164230} {id=17860389, code=200, status=10, create_date=20170117092203} {id=17895181, code=100, status=20, create_date=20170117192521} {id=17895389, code=100, status=20, create_date=20170117201327} {id=17892298, code=200, status=10, create_date=20170117000552}
最後に全体のソースコードを記載しておきます。
package com.example.athena; import java.util.List; import java.util.Map; import java.util.Properties; import javax.sql.DataSource; import org.apache.tomcat.jdbc.pool.PoolConfiguration; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.jdbc.core.JdbcTemplate; @SpringBootApplication public class SampleAthenaApplication { public static void main(String[] args) { ConfigurableApplicationContext ctx = SpringApplication.run(SampleAthenaApplication.class, args); SampleAthenaApplication app = ctx.getBean(SampleAthenaApplication.class); try { app.run(args); } catch (Exception e) { e.printStackTrace(); } } @Autowired private JdbcTemplate jdbc; @Autowired public void setDataSource(DataSource dataSource) { PoolConfiguration configuration = ((org.apache.tomcat.jdbc.pool.DataSource)dataSource).getPoolProperties(); Properties properties = configuration.getDbProperties(); properties.put("s3_staging_dir", "s3://cm-sample-bucket/results"); properties.put("log_path", "d://logs/test.log"); properties.put("aws_credentials_provider_class","com.amazonaws.auth.profile.ProfileCredentialsProvider"); properties.put("aws_credentials_provider_arguments","blog"); configuration.setDbProperties(properties); this.jdbc = new JdbcTemplate(dataSource); } public void run(String... args) throws Exception { List<Map<String, Object>> list = this.jdbc.queryForList("select id,code,status,create_date from default.custom。r limit 100"); list.forEach(System.out::println); } }
まとめ
いかがでしたでしょうか。SpringBootを使用することでAthenaへ接続も簡単にできたかと思います。今回のサンプルが参考になれば幸いです。今回は以上です。