Skip to content

[B05] A headerless CSV silently loses 1 row and is split into a separate _1 table with no warning #4

@ogawsh

Description

@ogawsh

[B05] ヘッダー無し CSV が混入するとデータ 1 行が静かに欠落し、別テーブル扱いになる(エラー無し)

再現条件

  • 同一プレフィックス配下に「ヘッダー有り CSV 9 ファイル」+「ヘッダー無し CSV 1 ファイル」を配置
  • Admin UI から analyzeapply
  • ヘッダー無しファイルは 1 行目からデータ行が始まる

観測された挙動

  • analyze は成功し 2 つのテーブルに分かれる
  • visits(9 ファイル)と visits_1(ヘッダー無しの 1 ファイル)に _deduplicate_table_names によるサフィックスで別テーブルとして CREATE
  • apply も SUCCEEDED(Step Functions SUCCEEDED, Admin UI も成功表示)
  • ロード後の実行件数:
    • visits: 9 ファイル × 100,000 行 = 900,000 行(期待値どおり)
    • visits_1: 1 ファイル 100,000 行 だが 99,999 行1 行消失

原因

1. _get_csv_header がヘッダー有無を判定せず、1 行目を常にヘッダーとして扱う

lambda/adminwebbackend/app.py _get_csv_header:

resp = s3.get_object(Bucket=bucket, Key=key, Range="bytes=0-8192")
raw = resp["Body"].read().decode("utf-8", errors="replace")
first_line = raw.split("\n", 1)[0].strip()
...
reader = csv.reader(io.StringIO(first_line), delimiter=delimiter)
headers = next(reader, None)
return headers
  • ファイル 1 行目の値(今回の例では V0000000000,P00039217,2024-01-01 00:00:00,内科,...)がそのまま「ヘッダー」として返る
  • _group_csv_by_headerヘッダー文字列が完全一致するファイル同士だけを同一グループにまとめるので、ヘッダー無しの CSV は必ず単独グループに分離される
  • Bedrock は 1 行目を「カラム名」として解釈して、適当な英名のカラム定義(visit_datetime, doctor_name, icd_code, diagnosis, remarks など)を生成してしまう
  • 結果、別名のカラムを持つ同一データ内容の別テーブル (visits_1) が作られる

2. COPY は IGNOREHEADER 1 固定なのでヘッダー無しファイルの 1 行目が失われる

handle_start_build で生成される COPY 文は常に IGNOREHEADER 1 を付けるため、ヘッダー無し CSV ではデータの 1 行目が捨てられ 1 行少なくなる(今回 100,000 → 99,999)。

  • Admin UI にはエラーも警告も出ないため、利用者は気づかない
  • 検知方法が select count(*) を手動で突き合わせる以外ない(サイレントなデータ欠損)

期待される挙動

  • ヘッダー行が無い CSV が混入したら検知して警告/エラーを上げる。具体的な案:
    • _get_csv_header が「2 行目以降のレコードと 1 行目のデータ型プロファイルを比較」し、一致度が高ければヘッダー無しと判定
    • または Admin UI の analyze プレビュー時点で「このカラム名は実データ値に見えます(例: V0000000000)」と警告する
    • _group_csv_by_header で孤立グループ(1 ファイルだけの group)が発生したら analyze 結果にそれを明示
  • COPY 側で IGNOREHEADER 1 を固定せず、analyze の判定結果に応じて 0 か 1 を動的に切り替える

再現手順

  1. 同一スキーマの CSV を 10 ファイル作成。そのうち 1 ファイル(例: visits_part4.csv)だけヘッダー行を削除する
  2. Admin UI から該当プレフィックスで Agent 作成 → analyze → apply
  3. select count(*) でヘッダー無しファイルの行数を確認すると N - 1 行になっていることを観測

参考情報

  • 対象スタック: arn:aws:cloudformation:ap-northeast-1:411521242467:stack/devDwhAgentStack/6619ffe0-3f8b-11f1-a3dc-068ad41190bd
  • SFn execution ARN: arn:aws:states:ap-northeast-1:411521242467:execution:AdminBackendInitWorkflowStateMachine4193125B-ArEyUWKHNQd8:b22592b0-902d-4c64-b447-879c825415f8
  • 関連ファイル: lambda/adminwebbackend/app.py _get_csv_header, _group_csv_by_header; lambda/redshiftinitworkflow/handlers.py COPY 生成箇所

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions