Amazon SageMakerからS3に保存したデータを操作する方法について(EMR,Glueを利用する)

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

概要

こんにちは、yoshimです。
今回はタイトルの通り、Amazon SageMakerからS3に保存したデータを操作する方法についてご紹介します。
基本的には下記の公式ドキュメントの通りですが、「新規にSageMakerインスタンスを作成する場合」、「既存のSageMakerインスタンスを利用する場合」の2パターンを検証してみました。
AWSの公式ドキュメント

目次

1.やることと構成について

1-1.やること

S3に保存したデータセットをGlueデータカタログに登録し、EMRクラスターで処理させた結果をSageMakerで取得する、ということをします。
なんでこんなことをやるのかというと、データセットを毎回SageMakerに保存して処理させる方法には限界があるため(ディスク容量等)、「データはS3に保存」しつつ「SageMakerで処理をさせたい」といったモチベーションからです。

今回はAWSの公式ドキュメントに用意されていたデータセットで試してみます。

1-2.構成

今回やることの構成図は下記の通りです。


参照:AWSの公式ドキュメント

SageMakerからクエリをEMRクラスターに投げて、EMRクラスターがGlueデータカタログに登録したデータ(S3に保存されている)を処理し、その結果をSageMakerインスタンスに返却します。

ドキュメントには、より詳細な挙動の説明がなされていました。

1.Amazon SageMaker を使用し、Jupyter の Sparkmagic ノートブックを起動させます。ノートブック内で、コマンドをローカルで実行するか、Amazon EMR クラスタで動作する Spark にコマンドを送信します。PySpark コマンドが使用でき、SQL magic で HiveQL コマンドを実行することもできます。
2.EMR クラスタに向けて送信されたコマンドが、同クラスタ上で動作する Livy サービスで受信されます。
3.Livy は、EMR クラスタで動作している Spark にコマンドを受け渡します。
4.Spark は、Hive メタストアにアクセスし、カタログ化されたデータセットのロケーション、スキーマ、プロパティを特定します。今回のケースでは、Hive メタストアは AWS Glue データカタログに設定されています。
5.Spark は Glue データカタログの情報を使用し、Amazon S3 のデータを直接読み込みます。
6.操作の実行後、Livy はさらなる解析と視覚化のために、データを Pandas のデータフレームとしてノートブックに戻します。

今回は、「新規にSageMakerインスタンスを作成する場合」と「既存のSageMakerインスタンスを利用する場合」の2パターンでやってみます。

2.新規にSageMakerインスタンスを作成する場合

手順はAWSの公式ドキュメントを参照してやっていきます。

2-0.すること

何をするのか、というのを最初に書いておきます。

・CloudFormationで「SageMakerインスタンス」、「Glueクローラ」、「EMRクラスター」を作成する。
・作成したGlueクローラから、対象のS3パス配下にあるデータを読み取り、データカタログに登録する。
・Glueデータカタログに登録されているデータをEMRクラスターで処理し、その結果をSageMakerインスタンスが取得する

2-1.CloudFormationスタックを起動

既に定義済みの「AWS CloudFormationスタック」が用意されているので、こちらを起動させます。

コンソール画面上から「CloudFormation」を開いて

「スタックの作成」をクリック

今回利用する「テンプレート URL」を指定して、「次へ」をクリックします。テンプレートURLは下記の通りです。

https://s3.amazonaws.com/aws-machine-learning-blog/artifacts/sageglues3/master-sageglue-template.yaml

続いて、「スタック名」、「VPC」、「VPCサブネット」の3点を指定します。
コンポーネントをダウンロードする必要があるので、パブリックサブネットを指定する必要がある点に注意してください。

SageMakerの「インスタンス名」、「config名(ライフサイクル設定名)」等を指定します。
SageMakerの「インスタンス名」、「config名」はアカウント&リージョンで一意になる必要がある点に注意してください。

今回はこんな感じで指定しました。
「Glue Parameters」の「DatasetsS3Path」には、Glueで読み込みたいデータが格納されているS3プレフィックスを指定しましょう。
また、S3プレフィックスの最後に「/」を入れておくと、指定したプレフィックス配下の全ファイルを読み込めます。
今回はチュートリアルのデータが格納されているS3プレフィックスを指定しますが、自分で用意したデータセットで試したい場合はこのS3プレフィックスを変更してください。

「次へ」をクリックするとオプションを指定できます。
必要であれば、IAMロールも指定しましょう。今回はとりあえず試してみたかっただけなので、IAMロールは指定せずに「タグの指定」のみをして先に進みました。

「AWS CloudFormation によってカスタム名のついた IAM リソースが作成される場合があることを承認します。」と出てくるので、利用しているAWSアカウントにおいて同名のIAMリソースが無いことを確認しましょう。
特に問題なさそうなら、チェックをして「作成」をクリックします。

スタックを作成します。
1つの親スタック(work-yoshim-sageglue)と3つの子スタック、計4つのスタックの「status」が「CREATE_COMPLETE」になったら準備完了です。

2-2.Glueクローラの実行

先ほど指定したS3のデータセットのメタデータを、Glueデータカタログに登録します。

コンソール画面からGlueの「クローラ」をクリックすると、先ほど作成したクローラがあるので、「クローラの実行」をクリックします。

クローラの実行が完了すると、S3に格納したファイルを読み込み、テーブルが追加されています。

これで、今回利用するデータセットがGlueのデータカタログとして認識されました。

2-3.SageMakerからGlueデータカタログに定義したデータへアクセス

「2-2.Glueクローラの実行」で作成したデータカタログにSageMakerからアクセスし、データフレームを取得します。 まず、コンソール画面上からSageMakerのインスタンスを確認すると、先ほど作成したインスタンスがあるので、このインスタンスをオープンします。

すると、最初から「Using_Amazon_SageMaker_to_access_Amazon_S3_Using_AWS_Glue_Data_Catalog.ipynb」というファイルが用意されています。
これは、今回利用したスタックで、このインスタンスの「ライフサイクル設定」で起動するたびにアップロードするように記述しているためです。
もし気になる場合は、このインスタンスに設定されているライフサイクル設定を確認するか「3-2.SageMakerのライフサイクル設定」をご参照ください。

この「Using_Amazon_SageMaker_to_access_Amazon_S3_Using_AWS_Glue_Data_Catalog.ipynb」ファイルを開いたら、少し中身を見てみましょう。
特に注目したいのは下記の3点です。

2-3-1.sparkとのセッションを確保する
import os
import platform
# Print some characteristics of the remote system
print(platform.node())
print(platform.platform(aliased=0, terse=0))
print("Spark home currently set to", os.environ.get('SPARK_HOME', None))
2-3-2.Glueデータカタログに指定したデータに対してクエリを実行する

SQLライクに処理内容を記述し、「membersadj」引数にデータフレーム形式で結果を取得します。
「-o」引数に指定した変数に結果を格納できます。

%%sql -o membersadj
select p.name as membername, p.gender, p.birth_date, p.death_date, 
    split(m.on_behalf_of_id,'/')[1] as party, split(m.legislative_period_id, '/')[1] as legislature,  
    o.name as orgname
from legislators.persons_json p
join legislators.memberships_json m on m.person_id = p.id
join legislators.organizations_json o on m.organization_id = o.id
2-3-3.取得した結果をローカルで利用する

「2.Glueデータカタログに指定したデータに対してクエリを実行する」で取得した結果が「membersadj」引数に格納されているので、この値を利用してSageMakerインスタンス上で処理を実行できます。

%%local
membersadj['gen'] = membersadj['gender'].map({'female': 1, 'male': 0})
membersadj['partynum'] = membersadj['party'].map({
    'republican-conservative':0, 
    'al':1,
    'republican':2,
    'democrat': 3,
    'popular_democrat':4,
    'new_progressive':5,
    'democrat-liberal':6,
    'independent':7  })

membersadj['legstart'] =(membersadj['legislature']*2 + 1767)
membersadj['birthyear'] = membersadj['birth_date'].dt.year
membersadj['age'] = membersadj['legstart'] - membersadj['birthyear']

membersadj.head()

「Using_Amazon_SageMaker_to_access_Amazon_S3_Using_AWS_Glue_Data_Catalog.ipynb」とは別のファイルで処理をしたい場合は、「kernel」を「SparkMagic (PySpark)」にする必要がある点に注意してください。

EMRで処理がなされていることはコンソール上の「EMR」→「アプリケーションの履歴」→「アプリケーションIDをクリック」といくと確認できます。

2-4.スタックを削除する

最後に、不要になった段階で上記で作成したスタックを削除しましょう。
削除する際は親スタック(今回の場合は「work-yoshim-sageglue」)を削除すれば、ネストされた子スタックも削除されます。

3.既存のSageMakerインスタンスを利用する場合

今回利用したテンプレートでは、SageMakerインスタンスを新規に作成していたのですが、もし既存のSageMakerインスタンスを使いたい場合は、下記の手順に沿ってください。

3-1.ClouFormationテンプレートから、EMRクラスターとGlueクローラを作成

今回のチュートリアルで利用したテンプレートからSageMakerインスタンスに関する部分を削除したテンプレートファイルを用意し、そのテンプレートファイルから「EMRクラスター」と「Glueクローラ」を作成します。

もしよかったらこちらのテンプレートをご利用ください。

3-2.SageMakerのライフサイクル設定

下記のようにライフサイクル設定を作成し、対象のSageMakerインスタンスに付与してください。
(<EMRクラスターのID>、<EMRクラスターがあるリージョン>のところを適宜変更してください)

前半部分はSageMakerでSparkmagicをセットアップするconfigファイルをダウンロードしたのち、EMRクラスターのIPを利用するように修正しています。

後半部分は「Using_Amazon_SageMaker_to_access_Amazon_S3_Using_AWS_Glue_Data_Catalog.ipynb」ファイルをダウンロードする、という処理なのですが、本ファイルが不要ならこの部分は削除してください。

#!/bin/bash
#set -€“e         
EMRGLUEIP=`aws emr list-instances --cluster-id <EMRクラスターのID> --instance-group-types MASTER --region <EMRクラスターがあるリージョン> | jq -r '.Instances[0].PrivateIpAddress' `

echo $(date +%F_%T) 'Using: <EMRクラスターのID>: ' $EMRGLUEIP

wget -O /home/ec2-user/SageMaker/.sparkmagic/config.json https://raw.githubusercontent.com/jupyter-incubator/sparkmagic/master/sparkmagic/example_config.json 
sed -i -e "s/localhost/$EMRGLUEIP/g" /home/ec2-user/SageMaker/.sparkmagic/config.json
# Next line needed to bypass 'failed to register auto_viz' error in recent version
sed -i -e 's/"use_auto_viz": true/"use_auto_viz": false/g' /home/ec2-user/SageMaker/.sparkmagic/config.json

wget -O /home/ec2-user/SageMaker/Using_Amazon_SageMaker_to_access_Amazon_S3_Using_AWS_Glue_Data_Catalog.ipynb https://s3.amazonaws.com/aws-machine-learning-blog/artifacts/sageglues3/Using_Amazon_SageMaker_to_access_Amazon_S3_Using_AWS_Glue_Data_Catalog.ipynb   
chmod +666 /home/ec2-user/SageMaker/Using_Amazon_SageMaker_to_access_Amazon_S3_Using_AWS_Glue_Data_Catalog.ipynb

また、SageMakerインスタンスに、EMRクラスターへ接続できる権限(IAMポリシー等)があることを確認してください。
接続ができたら、「2-3.SageMakerからGlueデータカタログに定義したデータへアクセス」同様に処理を実行できます。

4.まとめ

SageMakerからS3のファイルを操作することができるようになりました。

もし、「EMRを使うほどではないんだけど...」という場合はEMRの代わりにAthenaを使う構成を検討してもいいかもしれません。

5.引用

今回のチュートリアル手順の紹介エントリー
SageMakerでSparkmagicをセットアップ
SageMaker-Athena-Glueの構成