JMDC TECH BLOG

JMDCのエンジニアブログです

自動化に頼りすぎて失敗した話

こんにちは

データウェアハウス開発部 データレイクグループの大塚です。
ユーザ部門の方でも、AWSマネージメントコンソールの操作だけで要件を実現できないかチャレンジした結果、あと一歩のところでうまくいかなかった失敗談を紹介したいと思います。
自動化技術に頼りすぎると痛い目を見るよという参考になれば幸いです。

要件

ユーザ部門の方から下記2点の要望を受けました。

  1. 納品方式をOneDriveからS3に変更するタイミングでAthenaで利用できるようにしたい
  2. すぐに利用できるようにしたい

AsIs

OneDriveに納品された最大150ファイル程度のCSVをダウンロードして利用している

ToBe

S3に納品されたファイルをAthenaで分析できるようにしたい

構成案

下記の理由から、ユーザ部門の方と相談の上で、ノーコードで要件を実現できるGlue Crawlerを採用しました。

  • 時間をかけずに要件を実現する必要がある
  • 100件超あるファイルをテーブル化する処理を手動でやるのは大変
  • できる限りユーザ部門で運用を完結できるようにしたい

構成

Glue Crawlerの設定はエンジニアのサポートが必要

理想は「手順だけ作ってその手順をもとに誰でもすべての設定ができる」です

一見すると成功だが・・・

下記の通りAWSマネージメントコンソールのウィザードに従い、ユーザ部門の方と一緒に設定してみました。

  1. Set crawler properties
  2. Choose data sources and classifiers
  3. Configure security settings
  4. Set output and scheduling
  5. Review and create

実行したところあっさり成功!!

GlueCrawler実行結果

Athena上でもデータを取得できているようです。
簡単に実現できてGlue Crawler最高と思っていたのですが、後日ユーザ部門の方から一部テーブルがうまく読めてないと問い合わせがあり、調べてみると1行目にヘッダー行が含まれてしまっているテーブルがいくつかありました。


例.ヘッダー行が1行目に含まれる

col0 col1 col2
項目名イ 項目名ロ 項目名ハ
xxx ○○○ あいうえお
yyy □□□ かきくけこ

原因

データ行がすべて文字列の場合に、ヘッダー行を認識できない仕様のようです。
公式ページには下記の記載がありました。

組み込み CSV 分類子

(公式ページから引用)

ヘッダー行は、データ行と十分に異なっている必要があります。 これを判断するには、1 つ以上の行が STRING 型以外として解析されることを確認します。 すべての列が STRING 型である場合、最初のデータ行は以降の行と十分に異なっていないため、 ヘッダーとして使用できません。



ここからが茨の道の始まりです。
いくつか代替案は見つかるものの採用には至りませんでした。

代替案1(Classfier【分類子】を使う)

  • Column headingsオプションにHas Headingsを設定する

採用しなかった理由

  • Has Headingsオプションは列名をカンマ,区切りで明示的に指定する必要があり、列数やヘッダー列が同じテーブルが複数あるケースにしか使えない

代替案2(1行目をスキップするオプションの追加)

  • あとからSQLでヘッダー行を認識できていないテーブルに対して1行目をスキップするオプションを追加する
ALTER TABLE [tablename] SET TBLPROPERTIES ('skip.header.line.count' = '1');

採用しなかった理由

  • あとからSQLを実行する手間が増える
  • 列名がcol0colnとなり使いづらい


結果どうしたか

ノーコードを諦めてGlue ETL Jobsで簡単なETLジョブを作成することで実現しました。
実際コーディング作業はAI生成コードをほぼ採用する形で作成したのですが、 こちらもAIに頼りすぎてうまくいかなかった例を載せておきます。

AIコードの罠

AIへのインプット Glueで特定のバケット配下にあるCSVを解析して1行目をタイトル列にしてDDLを生成してテーブル作成するスクリプトのサンプルをください

AIのアウトプット(一部省略)

import boto3
from pyspark.sql import SparkSession

# 前半
# 特定パス配下のCSVをDataFrameで読込みながら型を取得してDDLを生成

# SparkSession の作成
spark = SparkSession.builder.getOrCreate()

# CSV ファイルのパス
bucket_name = 'your-bucket-name'
prefix = 'path/to/your/csv/files'

# S3 から CSV ファイルを読み込む
s3_path = f"s3://{bucket_name}/{prefix}"
df = spark.read.format("csv").option("header", "true").option("inferSchema", "true").load(s3_path)

# CSV ファイルのヘッダーを取得
headers = df.columns

# DDL を生成する
ddl = f"CREATE EXTERNAL TABLE IF NOT EXISTS your_table_name (\n"
for header in headers:
    data_type = df.schema[header].dataType.typeName()
    ddl += f"  {header} {data_type},\n"
    ddl = ddl.rstrip(",\n") + "\n) ROW FORMAT DELIMITED FIELDS TERMINATED BY ',' LOCATION 's3://{bucket_name}/{prefix}';"


# 後半
# AWS Glue にテーブルを作成(一部省略)
glue_client = boto3.client('glue')
database_name = 'your_database_name'
table_name = 'your_table_name'

table_input = {
    'Name': table_name,
    'StorageDescriptor': {
        'Location': f"s3://{bucket_name}/{prefix}",
        'InputFormat': 'org.apache.hadoop.mapred.TextInputFormat',
        'OutputFormat': 'org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat'
    },
    'TableType': 'EXTERNAL_TABLE'
}

glue_client.create_table(DatabaseName=database_name, TableInput=table_input)


コードを見て間違いに気づいた方はいたでしょうか。
よく見ると前半で生成したDDLを後半のテーブル作成で利用していないですね。 このコードを動かせるようにして実行したら、列がないテーブル名だけのテーブルが完成しました。

AI的には、2つの要件があると解釈した上でそれぞれ別の手法で提案して、 結果を1つのコードで返したという動きに見えました。

  • 前半:CSVから1行目をヘッダーとしたDDLを生成する
  • 後半:GlueでCSVからテーブルを作成する

追加対応

最終的には、追加でDDLAthena上で実行してテーブルを作成するコードを追加して完成となりました。

追加コード

athena = boto3.client('athena')

response = athena.start_query_execution(
    QueryString=ddl,
    QueryExecutionContext={
        'Database': f"{database_name}"
    },
    ResultConfiguration={
        'OutputLocation': f"s3://{bucket_name}/query_results/"
    }
)

前述のGlue Crawlerで作成したIAM RoleAthenaの実行権限を付与

理想は「Glueの権限のみで実現する」ですが、今回はこれ以上時間をかけられなかったのでこの対応としました。

実際には他にもS3の特定パス配下のオブジェクト数分繰り返すコードも追加



まとめ

CSVの1行目を確実にヘッダーとして利用したい場合はGlue Crawlerではできない 生成AIのコードは自力で修正できるかつ複数のコードをつなげるプログラミングスキルが必要



最後に

今回は失敗しましたが、スピーディに要件が実現できるのは自動化技術の強みであり、成功すればユーザ/システム部門がお互いに幸せになれるため、めげずに積極的にチャレンジしていきたいです。
また、構成案の採用理由で、ユーザ部門の方で運用を完結可能としているものの、AWSマネージメントコンソールを操作したりAthenaSQLを操作したりと、スキルのある方だから提案できた構成でした。 今回提案した構成を実際に設定手順としてまとめて、今後運用していくユーザ部門の方に改めて感謝しつつ終わりたいと思います。

最後まで、お読みいただきありがとうございました。




JMDCでは、ヘルスケア領域の課題解決に一緒に取り組んでいただける方を積極採用中です!詳細は下記の募集一覧からご確認ください。 hrmos.co まずはカジュアルにJMDCメンバーと話してみたい/経験が活かせそうなポジションの話を聞いてみたい等ございましたら、下記よりエントリーいただけますと幸いです。 hrmos.co ★最新記事のお知らせはぜひ X(Twitter)、またはBlueskyをご覧ください! twitter.com bsky.app