[AWS Glue]既存のGlueテーブルに対するクローラーをCloudFormationで作成してみた

2021.01.14

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

こんにちは、CX事業本部の若槻です。

AWS Glueではクローラーを使うことにより、指定したデータソースを解析して必要なパーティションやカラムなどのを持つGlueテーブルを自動作成し、継続的に更新させることができます。

一方で、手動で作成した既存のGlueテーブルを更新対象としたクローラーを作成することも可能です。

今回は、既存のGlueテーブルに対するクローラーをCloudFormationで作成してみました。

やってみた

まず最初に以降のコマンド実行で使用する変数を定義しておきます。

% AWS_REGION=ap-northeast-1
% ACCOUNT_ID=$(aws sts get-caller-identity | jq -r ".Account")
% RAW_DATA_BUCKET=s3://devices-raw-data-${ACCOUNT_ID}-${AWS_REGION}
% GLUE_DATABASE_NAME=devices_data_analystics
% RAW_DATA_GLUE_TABLE_NAME=devices_raw_data
% CRAWLER_NAME=devices-data-analytics

環境構築

動作確認環境を作成します。

CloudFormationスタック

CloudFormationスタックのテンプレートです。

template.yaml

AWSTemplateFormatVersion: '2010-09-09'

Resources:
  DevicesRawDataBucket:
    Type: AWS::S3::Bucket
    Properties: 
      BucketName: !Sub devices-raw-data-${AWS::AccountId}-${AWS::Region}

  DevicesDataAnalyticsGlueDatabase:
    Type: AWS::Glue::Database
    Properties: 
      CatalogId: !Ref AWS::AccountId
      DatabaseInput:
        Name: devices_data_analystics

  DevicesRawDataGlueTable:
    Type: AWS::Glue::Table
    Properties:
      CatalogId: !Ref AWS::AccountId
      DatabaseName: !Ref DevicesDataAnalyticsGlueDatabase
      TableInput:
        Name: devices_raw_data
        TableType: EXTERNAL_TABLE
        Parameters:
          has_encrypted_data: false
          serialization.encoding: utf-8
          EXTERNAL: true
        StorageDescriptor:
          OutputFormat: org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat
          Columns:
            - Name: device_id
              Type: string
            - Name: timestamp
              Type: bigint
            - Name: state
              Type: boolean
          InputFormat: org.apache.hadoop.mapred.TextInputFormat
          Location: !Sub s3://${DevicesRawDataBucket}/raw-data
          SerdeInfo:
            Parameters:
              paths: device_id, timestamp, state
            SerializationLibrary: org.apache.hive.hcatalog.data.JsonSerDe
        PartitionKeys:
          - Name: year
            Type: string
          - Name: month
            Type: string
          - Name: day
            Type: string

  DevicesDataAnalyticsGlueCrawler:
    Type: AWS::Glue::Crawler
    Properties:
      Name: devices-data-analytics
      Role: !Sub arn:aws:iam::${AWS::AccountId}:role/service-role/AWSGlueServiceRole-DefaultRole
      Targets:
        CatalogTargets:
          - DatabaseName: !Ref DevicesDataAnalyticsGlueDatabase
            Tables:
              - !Ref DevicesRawDataGlueTable
      SchemaChangePolicy:
        DeleteBehavior: LOG

DevicesDataAnalyticsGlueCrawlerがクローラーのリソース定義となります。Properties.Targets.CatalogTargetsでクロール対象としたい既存のGlueテーブルを指定できます。

Properties.SchemaChangePolicy.DeleteBehaviorは、ドキュメントだと指定は必須となっていませんが、指定しない場合になぜか下記のエラーとなるのでLOGを指定しています。

The SchemaChangePolicy for catalog targets can have only LOG DeleteBehavior value. Specify a value of LOG for the DeleteBehavior property.

クロール対象とするGlueテーブルDevicesRawDataGlueTableのリソース定義では、Properties.TableInput.PartitionKeysにてyearmonthdayの3つをパーティションキーとして指定しています。

スタックをデプロイします。

% aws cloudformation deploy \
  --template-file template.yaml \
  --stack-name devices-data-analytics-stack \
  --capabilities CAPABILITY_NAMED_IAM \
  --no-fail-on-empty-changeset

データソースへのデータ作成

データソースのデータとして、Hive形式のパーティションパスを持つオブジェクトをS3バケットに作成します。

raw-data.json

{"device_id": "3ff9c44a", "timestamp": 1609348014, "state": true}
% aws s3 cp raw-data.json \
  ${RAW_DATA_BUCKET}/raw-data/year=2021/month=01/day=13/raw-data.json

動作確認

クローラー実行前はGlueテーブルにパーティションは一つも作成されていません。

% aws glue get-partitions \
  --database-name ${GLUE_DATABASE_NAME} \
  --table-name ${RAW_DATA_GLUE_TABLE_NAME}

{
    "Partitions": []
}

クローラーを実行します。

% aws glue start-crawler --name ${CRAWLER_NAME}

クローラーのステートがREADYとなれば実行は完了です。

% aws glue get-crawler --name ${CRAWLER_NAME} \
  --query Crawler.State

"READY"

再度Glueテーブルのパーティションを取得してみると、アップロードしたオブジェクトで指定したパスのパーティションが作成されています。

% aws glue get-partitions \
  --database-name ${GLUE_DATABASE_NAME} \
  --table-name ${RAW_DATA_GLUE_TABLE_NAME} \
  --query 'Partitions[0].Values'

[
    "2021",
    "01",
    "13"
]

おわりに

既存のGlueテーブルに対するクローラーをCloudFormationで作成してみました。

当初クローラーで自動更新を行いたいGlueテーブルはクローラーで作成しないといけないと思い込んでいましたが、調査・検証してみると既存のGlueテーブルの更新にも対応していて良かったです。

参考

以上