[初心者向け]Amazon Redshift内のデータをできる限り楽にSpectrum化してみた

去年行われたre:Invent2019の2日目のキーノートでAmazon Redshift の新機能「Data Lake Export」が発表されました。
[速報] Amazon Redshift の新機能「Data Lake Export」でParquet形式にUNLOADできるようになりました #reinvent | Developers.IO

これにより自前で変換プログラムを用意せずともs3へのparquetファイル形式で出力することが可能になりました。
自前で作る必要なくなったよ、やったね!

そこで今回は、できる限り楽してAmazon Redshift上のデータをparquet形式のファイルにしてAmazon Redshift Spectrum化できるかやってみました。

作業一覧

1) テスト用データ作成
3) Amazon Redshift用のIAMロールの作成
3) 作成したIAMロールを設定する
4) UNLOAD先バケットの準備
5) parquet形式のUNLOADを行う
6) 外部スキーマの作成
7) Glueのクローラを使う
8) データの確認

 

テスト用データ作成

おなじみのステップ 6: Amazon S3 のサンプルデータをロードする - Amazon Redshiftのデータを使います。

 

Amazon Redshift用のIAMロールの作成

Amazon Redshift用に割り振る、S3とGlueへのアクセス権を設定したIAMロールを作成します。

Managed Consoleを開き、IAMのページに移動し、左側から[ロール]を選択し、[ロールの作成]を押下します。

[サービスの選択]で"Redshift"を選択し、[ユースケースの選択]では"Redshift - Customizable"を選択します。右下の次へボタンを押下します。

アクセス付与として[ポリシーのフィルタ]に"AmazonS3FullAccess"と入力し、同ポリシーが表示されたらチェックを入れます。

今度は[ポリシーのフィルタ]に"AWSGlueConsoleFullAccess"と入力して同じようにチェックを入れます。

[ロールの作成]画面では[ロール名]を記載し、[ロールの作成]を押下します。

これでAmazon Redshiftへ追加するロールが完成しました。
次の手順に進む前にロールARNを確認します。

ロールを選択すると概要ページに遷移しますので、ロールARNをどこかにコピーしておきます。

 

Amazon Redshiftに作成したIAMロールを追加する

続いて、Amazon Redshiftのクラスタに作成したIAMロールを追加する作業を行います。

[クラスター]を選択し、一覧から対象のクラスターを選択します。

[プロパティ]タグを選択し、[クラスターのアクセス許可]の[IAMロールの管理]を押下します。

[IAMロール]にて先ほど作成したロールを選択し、[IAMロールを追加]を押下します。

IAMロール一覧にロールが追加されていることを確認したら[Done]を押下します。

[クラスターのアクセス許可]のアタッチされたIAMロール の一覧に追加されていることを確認します。
※最初は状態が"adding"ですが時間経過で"in-sync"になります。


これでAmazon Redshiftへのロール設定は完了です。

 

UNLOAD先バケットの準備

最後の事前準備としてUNLOAD先のバケットを用意します。
このとき、Redshiftと同じリージョン を指定してバケットを作成します。


※UNLOAD自体は別リージョンのバケットを指定して実行することも可能です。
しかし、Spectrum用のデータは同じリージョンのs3を使う必要があります。
(別リージョンのデータを指定すると最後の最後でエラーが出て悲しいことになります(なった))

 

parquet形式のUNLOADを行う

ついにUNLOADコマンドの実行です。
今回は以下のsqlを実行します。

UNLOAD ('
  SELECT sales.*, date.*, total_price, percentile
    FROM sales, date, (
      SELECT eventid,total_price, ntile(1000) over (order by total_price desc) / 10.0 as percentile
        FROM (
          SELECT eventid, sum(pricepaid) total_price
            FROM sales
           GROUP BY eventid
        )
    ) as percentile_events
   WHERE sales.dateid = date.dateid
     AND percentile_events.eventid = sales.eventid
')
TO 's3://cm-a-iwa-spectrum-test/DataLake/SalesPartitioned/'
FORMAT AS PARQUET
PARTITION BY (year, caldate)
CREDENTIALS 'aws_iam_role=arn:aws:iam::123412341234:role/XXXXXXXXXXXXXXRole'
;

実行結果はこんな感じになります。

 

外部スキーマの作成

外部スキーマ("cm_a_iwa_spectrum_testdb")の作成を行います。 同時にGlueのDataCatalogにデータベース("cm_a-iwa_db")を登録します。

CREATE EXTERNAL SCHEMA cm_a_iwa_spectrum_testdb FROM DATA CATALOG 
DATABASE 'cm_a-iwa_db'
IAM_ROLE 'arn:aws:iam::123412341234:role/XXXXXXXXXXXXXXRole'
CREATE EXTERNAL DATABASE IF NOT EXISTS;

Managed ConsoleにてGlueのページを開き、データベース"cm-a-iwa-spectrum-testdb"が登録されていることを確認します。

 

クローラの作成と実行

最後にGlueのクローラを作成・実行し、DataCatalogにテーブルを登録します。

左ナビゲーションペインより[クローラ]を選択し、[クローラの追加]を押下します。

[クローラの情報]では[クローラの名前]を設定し(ここでは"cm_a-iwa_crawler"をしています)、[次へ]を押下します。

[Crawler source type]では"Data stores"を選択し、[次へ]を押下します。

[データストア]では
[データストアの選択]:"S3"
[クロールするデータの場所]:"自分のアカウントで指定されたパス"
[インクルードパス]:UNLOADコマンドのTO句で指定したprefix
を設定し、[次へ]を押下します。

[別のデータストアの追加]は"いいえ"を選択し、[次へ]を押下します。

[IAM ロールの選択]では"IAMロールを作成する"を選択し、ロール名を入力します(画像では"cm-a-iwa-spectrum-test")。[次へ]を押下します。

[このクローラのスケジュールを設定する]では実行スケジュールを設定します。
今回は手動で実行するので[頻度]を"オンデマンドで実行"を選択します。
[次へ]を押下します。

[クローラの出力を設定する]ではテーブルを追加するデータベースを設定します。
[データベース]にはRedshiftにて外部スキーマを作成際に設定した名称(例では"cm_a-iwa_db")を設定します。
[次へ]を押下します。

最後に確認画面が表示されるので、設定を確認して問題なければ[完了]を押下します。

これでクローラができました。一覧から作成したクローラにチェックをつけ、[クローラの実行]を押下します。

左ナビゲーションペインより[データベース]の[テーブル]にて、 テーブルが追加されたことが確認できます。

 

確認してみる

それではSQLを実行して確認してみます。

無事、データ取得できました。

最後に

UNLOADファイルのparquet化プログラムを作成する必要がなくなったので、出力クエリと外部スキーマの作成だけで簡単にSpectrum化することができました。
Glueのクローラは周期実行の設定も可能ですので、集計用SQLを周期実行している環境ならば、集計処理結果をSpectrum化することも簡単かと思います。

それではまた!

おまけ:別リージョンにあるs3のバケットを指定すると?

UNLOADコマンドはREGION句があり、別リージョンへ出力することも可能です(時間はかかりますが)。
また外部スキーマ作成時に、別リージョンにあるGlue Catalogのデータベースを指定することも可能です。

クローラの作成時にも、別リージョンのs3を選択するとエラーメッセージが表示されます。

ですがを直接記述すると別リージョンのs3を指定できます。

そうして別リージョンのs3を参照したテーブルに対してクエリを実行すると...?

XX000: S3 Query Exception: 
  -----------------------------------------------
  error:  S3ServiceException:The S3 bucket addressed by the query is in a different region from this cluster.,Status 301,Error PermanentRedirect,Rid 616129725D1FE41C,ExtRid VB2RxbEl9uNn

はい、エラーが返ってきます。動きません。一回ひっかかりました。

Amazon Redshift Spectrum に関する考慮事項に、 Amazon Redshift クラスターおよび Amazon S3 バケットは同じ AWS リージョンに存在する必要があります。 と記載があります。

ですので、このエラーメッセージを見た際はリージョンを確認するといいと思います。 今度こそ...それではまた!

参考文献