RDS for MySQLでAmazon Machine LearningのDatasourceを作ってみた

Amazon Machine Learning

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

RDS for MySQLからAmazon Machine Learning(Amazon ML)のDatasourceを作成する手順について試してみました。公式ドキュメントのUsing Amazon RDS with Amazon MLに書かれている手順です。なお、現状はRDSに関してはマネジメントコンソールからのDatasourceの作成は実装されておらず、APIを利用する必要があります。そのため、今回はAWS CLIを利用してDatasourceを作成しています。

仕組み

RDSからDatasourceを作成する場合は、Data Pipelineを利用する仕組みになっていました(゚д゚)!Amazon MLのCreateDataSourceFromRDS APIを実行すると、Amazon MLサービスが以下の処理を実行します。

  1. Amazon MLサービスがData Pipeline上に新規のPipelineを作成する
    1. CopyActivityによってEC2インスタンスが起動する
    2. EC2インスタンスからRDSに対してSQLを発行しS3に結果をCSVファイルとして保存する
  2. Amazon MLサービスがS3上のCSVファイルをDatasourceとして読み込む

そのため、事前に以下の準備が必要になります。

  • RDSのセキュリティグループをData Pipelineによって起動されるEC2インスタンスからアクセス可能にしておく
  • Data Pipelineの初回のセットアップ(IAM Roleの準備)
  • S3バケットの作成
  • Amazon ML用のIAM Roleの作成

また、DatasourceのData Schemaについても準備する必要があります1。マネジメントコンソールからS3上のCSVファイルを読み込む場合はAmazon ML側が自動でData Schemaの雛形を作成してくれるのですが、API経由の場合は編集するタイミングがないためData SchemaのJSONを指定する必要があります。

前提

まずは今回の手順の前提の確認です。RDS for MySQLは作成済みで、test_dbbankingテーブルが存在している前提です。bankingテーブルはAmazon MLのチュートリアルに載っているbanking.csvに対応しています。また、リージョンはAmazon MLが利用可能なバージニアを利用しています。

項目
リージョン バージニア(us-east-1)
RDSのEngine MySQL 5.6.23
RDSのInstanceIdentifier test-mysql
MySQLのデータベース test_db
MySQLのテーブル banking

bankingテーブルのDDLは以下の通りです。とりあえず動作すれば良いという割り切りで作っています。

CREATE TABLE banking
(
  age              INT,
  job              VARCHAR(20),
  marital          VARCHAR(20),
  education        VARCHAR(20),
  defalut          VARCHAR(20),
  housing          VARCHAR(20),
  loan             VARCHAR(20),
  contact          VARCHAR(20),
  month            VARCHAR(20),
  day_of_week      VARCHAR(20),
  duration         INT,
  campaign         INT,
  pdays            INT,
  previous         INT,
  poutcome         VARCHAR(20),
  emp_var_rate     FLOAT,
  cons_price_idx   FLOAT,
  cons_conf_idx    FLOAT,
  euribor3m        FLOAT,
  nr_employed      FLOAT,
  y                INT
);

banking.csvをbankingテーブルにインポートする際はLOAD DATA LOCAL INFILEコマンドなどが利用できます。

LOAD DATA LOCAL INFILE 'banking.csv' INTO TABLE banking FIELDS TERMINATED BY ',' ENCLOSED BY '"' LINES TERMINATED BY '\n'  IGNORE 1 LINES;

Data Pipelineの初回のセットアップ

この手順はData Pipelineの初回セットアップが完了している場合は不要です。具体的にはDataPipelineDefaultRoleDataPipelineDefaultResourceRoleを作成します2。詳細は公式ドキュメントのSetting Up for AWS Data Pipelineをご参照下さい。マネジメントコンソール上でData Pipelineを作成すると自動的に作成されます。もしくは先程の公式ドキュメントの手順に沿って手動で作成して下さい。

Amazon ML用のIAM Roleの作成

RDSの場合はAmazon MLサービスにData PipelineとAmazon MLの操作を行ってもらう形になるためAmazon MLサービスがAssumeRole可能なIAM Roleを作成する必要があります3。具体的には公式ドキュメントのIAM Role Used to Create, Activate, and Execute the Data Pipelineに書かれている手順になります。

以下の留意事項に沿ってマネジメントコンソール上でIAM Roleを作成して下さい。

  • APIを呼び出すときはRoleのARNを利用するため[Role Name]は任意です。例えばAmazon_MLなどとします。
  • [Select Role Type]ではAmazon Machine Learning Role for Redshift Data Sourceを指定します。Redshiftと書かれていますがTrust RelationshipはRDSで利用する場合と同じ内容になっています。具体的には以下の設定内容になります。
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "",
      "Effect": "Allow",
      "Principal": {
        "Service": "machinelearning.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}
  • Inline Policyを指定するため[Attach Policy]の画面でAmazonMachineLearningRoleforRedshiftDataSourceへのチェックは不要です。
  • Role作成後にInline PolicyとしてPolicyを設定します。編集する部分はs3:ListBuckets3:GetObjectYOUR_BUCKET_NAMEの箇所です。要はAmazon MLサービスから利用するS3バケットのCSVファイルにアクセスするための権限を設定しておけばよいことになります。そのため、S3バケット側のBucket Policyで許可している場合はInline Policy側での指定は不要です4
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "rds:DescribeDBInstances",
                "rds:DescribeDBSecurityGroups",
                "datapipeline:DescribeObjects",
                "datapipeline:CreatePipeline",
                "datapipeline:PutPipelineDefinition",
                "datapipeline:ActivatePipeline",
                "datapipeline:DescribePipelines",
                "datapipeline:QueryObjects",
                "iam:PassRole"
            ],
            "Resource": [
                "*"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:ListBucket"
            ],
            "Resource": [
                "arn:aws:s3:::YOUR_BUCKET_NAME"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:GetObject"
            ],
            "Resource": [
                "arn:aws:s3:::YOUR_BUCKET_NAME/*"
            ]
        }
    ]
}

Data Schemaの作成

CreateDataSourceFromRDS APIを実行する際にData Schemaの指定が必要になります。今回は手抜きをして既にAmazon ML上に手動で作成していたbanking.csvのDatasourceからData Schemaを取得したいと思います。なお、通常はSQLに対応するDatasourceがAmazon ML上に存在しないと思いますので手動で作成する必要があります。

既存のDatasourceからData Schemaを取得する際はAWS CLIのget-data-sourceサブコマンドを利用します。--verboseオプションを付けないとData Schemaが返却されないので注意して下さい。

$ aws --region us-east-1 machinelearning get-data-source --data-source-id ds-XXXX --verbose
{
    "Status": "COMPLETED", 
    "NumberOfFiles": 1, 
    "Name": "Banking.csv", 
    "DataLocationS3": "s3://XXXX/banking.csv", 
    "CreatedByIamUser": "arn:aws:iam::XXXX:user/XXXX", 
    "DataSizeInBytes": 4882918, 
    "ComputeStatistics": true, 
    "LastUpdatedAt": 1441095221.387, 
    "DataSourceId": "ds-XXXX", 
    "LogUri": "https://eml-prod-emr.s3.amazonaws.com/XXXX", 
    "DataSourceSchema": "{\"version\":\"1.0\",\"rowId\":null,\"rowWeight\":null,\"targetAttributeName\":\"y\",\"dataFormat\":\"CSV\",\"dataFileContainsHeader\":true,\"attributes\":[{\"attributeName\":\"age\",\"attributeType\":\"NUMERIC\"},{\"attributeName\":\"job\",\"attributeType\":\"CATEGORICAL\"},{\"attributeName\":\"marital\",\"attributeType\":\"CATEGORICAL\"},{\"attributeName\":\"education\",\"attributeType\":\"CATEGORICAL\"},{\"attributeName\":\"default\",\"attributeType\":\"CATEGORICAL\"},{\"attributeName\":\"housing\",\"attributeType\":\"CATEGORICAL\"},{\"attributeName\":\"loan\",\"attributeType\":\"CATEGORICAL\"},{\"attributeName\":\"contact\",\"attributeType\":\"CATEGORICAL\"},{\"attributeName\":\"month\",\"attributeType\":\"CATEGORICAL\"},{\"attributeName\":\"day_of_week\",\"attributeType\":\"CATEGORICAL\"},{\"attributeName\":\"duration\",\"attributeType\":\"NUMERIC\"},{\"attributeName\":\"campaign\",\"attributeType\":\"NUMERIC\"},{\"attributeName\":\"pdays\",\"attributeType\":\"NUMERIC\"},{\"attributeName\":\"previous\",\"attributeType\":\"NUMERIC\"},{\"attributeName\":\"poutcome\",\"attributeType\":\"CATEGORICAL\"},{\"attributeName\":\"emp_var_rate\",\"attributeType\":\"NUMERIC\"},{\"attributeName\":\"cons_price_idx\",\"attributeType\":\"NUMERIC\"},{\"attributeName\":\"cons_conf_idx\",\"attributeType\":\"NUMERIC\"},{\"attributeName\":\"euribor3m\",\"attributeType\":\"NUMERIC\"},{\"attributeName\":\"nr_employed\",\"attributeType\":\"NUMERIC\"},{\"attributeName\":\"y\",\"attributeType\":\"BINARY\"}],\"excludedAttributeNames\":[]}", 
    "CreatedAt": 1441094889.499
}

CreateDataSourceFromRDS APIの実行

では事前準備は完了したので、CreateDataSourceFromRDS APIを実行してRDSからDatasourceを作成しましょう。AWS CLIの場合はcreate-data-source-from-rdsサブコマンドになります。なお、create-data-source-from-rdsサブコマンドは引数が多いため--cli-input-jsonオプションを利用してJSONファイル経由で引数を指定しています5

$ aws --region us-east-1 machinelearning create-data-source-from-rds --cli-input-json file://test_create-data-source-from-rds.json
{
    "DataSourceId": "banking_from_rds_mysql"
}

test_create-data-source-from-rds.jsonの中身は以下のようになっています。

{
    "DataSourceId": "banking_from_rds_mysql",
    "DataSourceName": "Banking",
    "RDSData": {
        "DatabaseInformation": {
            "InstanceIdentifier": "test-mysql",
            "DatabaseName": "test_db"
        },
        "SelectSqlQuery": "SELECT * FROM banking ORDER BY rand()",
        "DatabaseCredentials": {
            "Username": "test_user",
            "Password": "****"
        },
        "S3StagingLocation": "s3://YOUR_BUCKET_NAME/YOUR_BASE_PATH/",
        "DataSchema": "{\"version\":\"1.0\",\"rowId\":null,\"rowWeight\":null,\"targetAttributeName\":\"y\",\"dataFormat\":\"CSV\",\"dataFileContainsHeader\":true,\"attributes\":[{\"attributeName\":\"age\",\"attributeType\":\"NUMERIC\"},{\"attributeName\":\"job\",\"attributeType\":\"CATEGORICAL\"},{\"attributeName\":\"marital\",\"attributeType\":\"CATEGORICAL\"},{\"attributeName\":\"education\",\"attributeType\":\"CATEGORICAL\"},{\"attributeName\":\"default\",\"attributeType\":\"CATEGORICAL\"},{\"attributeName\":\"housing\",\"attributeType\":\"CATEGORICAL\"},{\"attributeName\":\"loan\",\"attributeType\":\"CATEGORICAL\"},{\"attributeName\":\"contact\",\"attributeType\":\"CATEGORICAL\"},{\"attributeName\":\"month\",\"attributeType\":\"CATEGORICAL\"},{\"attributeName\":\"day_of_week\",\"attributeType\":\"CATEGORICAL\"},{\"attributeName\":\"duration\",\"attributeType\":\"NUMERIC\"},{\"attributeName\":\"campaign\",\"attributeType\":\"NUMERIC\"},{\"attributeName\":\"pdays\",\"attributeType\":\"NUMERIC\"},{\"attributeName\":\"previous\",\"attributeType\":\"NUMERIC\"},{\"attributeName\":\"poutcome\",\"attributeType\":\"CATEGORICAL\"},{\"attributeName\":\"emp_var_rate\",\"attributeType\":\"NUMERIC\"},{\"attributeName\":\"cons_price_idx\",\"attributeType\":\"NUMERIC\"},{\"attributeName\":\"cons_conf_idx\",\"attributeType\":\"NUMERIC\"},{\"attributeName\":\"euribor3m\",\"attributeType\":\"NUMERIC\"},{\"attributeName\":\"nr_employed\",\"attributeType\":\"NUMERIC\"},{\"attributeName\":\"y\",\"attributeType\":\"BINARY\"}],\"excludedAttributeNames\":[]}",
        "ResourceRole": "DataPipelineDefaultResourceRole",
        "ServiceRole": "DataPipelineDefaultRole",
        "SubnetId": "subnet-XXXX",
        "SecurityGroupIds": [
            "sg-XXXX"
        ]
    },
    "RoleARN": "arn:aws:iam::XXXX:role/Amazon_ML",
    "ComputeStatistics": true
}
  • DataSourceIdは任意の文字列を指定して下さい。なお、マネジメントコンソールからDatasourceを作成した場合はAmazon ML側で自動的に設定されます。
  • SelectSqlQueryはデータを抽出するためのSQLを記述します。なおORDER BY rand()については公式ドキュメントにおいて指定することを推奨する旨が記述されていました。予めデータの順序をランダムにした方が学習時の精度が向上するとのことです。
  • S3StagingLocationはCSVを保存する際のベースとなるパスです。YOUR_BUCKET_NAMEYOUR_BASE_PATHを変更して下さい。
  • DataSchemaget-data-sourceサブコマンドで取得したJSONの文字列をそのまま貼っています。
  • ResourceRoleServiceRoleはData Pipelineが利用するRoleです。
  • SubnetIdSecurityGroupIdsはData Pipelineが起動するEC2インスタンスに適用されます。そのため、このサブネットとセキュリティグループからRDSにアクセス可能にしておく必要があります。
  • RoleARNはAmazon ML用に作成したIAM RoleのARNを指定します。

ということで実際にData Pipelineが実行されたスクリーンショットを貼っておきます。 rds-for-mysql-with-amazon-machine-learning1

まとめ

いかがだったでしょうか。マネジメントコンソールからS3上のCSVファイルを使ってDatasourceを作成するのは非常に簡単なのですが、RDSの場合は初回の準備はかなり大変かと思います。実際、私が試した際もIAM Role周りとData Pipeline周りで何度かエラーになりました。ですが、一度仕組みができてしまえば流用可能ですので、今回のエントリーが参考になれば幸いです。


  1. Data Schemaの詳細はAmazon Machine Learningで自動生成されたData Schema JSONを確認するをご参照下さい。 
  2. 正確には必要な権限が設定されていれば任意のRoleでも問題ありません。 
  3. AssumeRoleの詳細はIAMロール徹底理解 〜 AssumeRoleの正体をご参照下さい。 
  4. 逆に言うとBucket Policyを設定している場合はInline Policyでアクセス許可をしてもBucket Policyの設定内容でAmazon MLサービスからのアクセスが拒否される可能性があるのでご注意下さい。実際、私はそこで一度エラーになりました(´・ω・`) 
  5. --cli-input-jsonの詳細はAWS CLIのパラメータをJSONファイルで記述するをご参照下さい。