TT Lab
はじめる
学ぶ 学習パス コース

データパイプライン

系譜と再現 — 二度動かしてバイトが同じか

TT Labで続きを見る

目標

毎日落ちてくる注文ドロップを集計する変換ツールlineage.pyを作ります。出力物ごとに、どの入力(コンテンツハッシュ)と、どのコードと、どのパラメーターで作られたかをマニフェストに残し、同じ入力で2回回して、バイトが同じかを証明し、カラム1つがどの入力カラムから来たかを、実験で確認します。

なぜ重要なのか

レポートの数字が経理とずれたときに、答える必要がある問いは1つです。この数字はどこから来たのか。ファイル名と更新時刻では答えられません。名前は同じなのに上流が上書きした場合がよくあり、更新時刻は、コピーだけでも変わります。根拠になるのは、内容そのもののハッシュです。そして、「もう一度回してみよう」が通用するには、同じ入力が同じ出力を出す必要があります。それは自然には成り立ちません。出力物に書き込んだ現在時刻、実行ごとに新しく作った識別子、ソートしていないファイルの一覧と集合の走査、浮動小数点を足す順序が、静かに再現を壊します。このラボは、その4つを1つずつ見つけて取り除きます。リネージには、粒度もあります。データセット単位は、「この表は、あの3つのファイルから来た」までで、カラム単位は、「このカラムは、あの入力カラムから来た」までです。上流がカラム1つを変えると知らせてきたときに、答えられる粒度は、後者です。そして、カラムのリネージは、書いておくとすぐに古くなるため、実験でもう一度測ります。採点ツールは、提出された文言を信じません。一時ディレクトリに、採点ツールが作ったドロップを用意して、自分で作った変換ツールを実際に実行し、集計値とマニフェストを、採点ツールが直接数えた値と突き合わせ、2回回してバイトを比べ、入力カラムを1つずつ揺らして、自分で書いたカラムのリネージと合っているかを確認します。店舗と金額は、実行ごとに変わります。

ステップ

  1. /root/lineage/gen_drops.pyを作成して実行し、/root/lineage/dropsの下に、日付ごとのドロップを3つ作ってください。
  2. /root/lineage/lineage.pyにdigestを作り、コンテンツハッシュとサイズとレコード数を出力させてください。
  3. runを追加して、集計の出力物/root/lineage/out/shops.csvを出力させてください。
  4. run --manifestで、マニフェスト/root/lineage/out/shops.manifest.jsonを一緒に出力させてください。
  5. 2回回してバイトが同じになるように直し、その結果を/root/lineage/repro.jsonに残してください。
  6. columnsを追加して、カラム単位のリネージを出力し、/root/lineage/columns.jsonに残してください。
  7. verifyを追加して、マニフェストどおりに作り直して、突き合わせさせてください。
  8. traceを追加して、/root/lineage/lineage_report.mdを書いてください。

参考

毎日落ちてくるドロップを作る

/root/lineage/gen_drops.pyを作成して実行し、/root/lineage/dropsの下に、日付ごとのドロップを3つ作ってください。ヘッダーはorder_id,shop,qty,amount,dropped_atで、数量が0の行と、同じ伝票が金額だけ変わってもう一度来た行が、混ざっている必要があります。

現場では、ファイルが先にあります。ここでは、そのファイルを私たちが作ります。店舗は4つ以上、店舗ごとに受け入れられる行が3つ以上あり、伝票番号の1つは、異なる2つのファイルに出てくる必要があります。dropped_atは、集計が使わないカラムなので、値が複数種類あればよいです。

名前ではなく内容で同一性を判定する

/root/lineage/lineage.pyにdigest <파일>(プレースホルダーはファイルです)を作り、path・sha256・bytes・rowsをJSONで出力させてください。rowsは、ヘッダーを除いたレコード数です。

ファイルをバイナリで小分けにして読み、hashlib.sha256に入れます。同じ内容を別の名前でコピーしたり、touchで更新時刻だけを変えたりしてみて、ハッシュがそのままかを自分で確認してください。レコード数は、行数ではなく、csvで数える必要があります。

集計の出力物を出す

run --drops <디렉터리> --out <파일> [--min-qty N](プレースホルダーは、ディレクトリとファイルです)を追加して、/root/lineage/out/shops.csvを出力させてください。ファイルを名前順に読み、同じ伝票は最初に出た行だけを残し、そのあとqtyがmin_qty未満の行を捨て、shopでまとめて、shop,orders,qty,amount_centsを、店舗の昇順で書きます。

重複排除を数量のフィルターより先に行うという点が、答えを変えます。最初に出た行の数量が0なら、その伝票は丸ごと抜けます。金額は、文字列を整数のセントに変えて足してください。ファイルの一覧は、ソートして読みます。os.listdirの順序は、約束されたものではありません。

出力物とマニフェストを一緒に出す

run --manifest <파일>(プレースホルダーはファイルです)を追加して、/root/lineage/out/shops.manifest.jsonを一緒に出力させてください。tool・code_sha256・drops_dir・params・inputs・output・run_id・created_atの8つのキーを入れます。

入力は、名前順の一覧で、name・sha256・bytes・rowsを入れ、code_sha256は、lineage.py自身のハッシュです。パラメーターは、デフォルト値も書いてください。デフォルト値は、あとで変わります。あとで付けると必ず抜けるため、出力物と同じ関数の中で作ってください。

2回回してバイトが同じか

同じ入力で2回回したときに、出力物のバイトが同じで、マニフェストがcreated_atを除くすべての欄で同じになるように直してください。そして、2回回した結果を、/root/lineage/repro.jsonにrun_a・run_b・identical・manifest_diff_keysとして残してください。

今のバージョンは、実行の識別子を乱数で作っているため、マニフェストが毎回違います。識別子は、内容から導出してください。コードのハッシュとパラメーターと出力のハッシュをつなげてハッシュすれば、同じ実行は同じ名前を持ちます。ファイルの一覧とグループの一覧をソートしたかも、もう一度見てください。Pythonは、実行ごとに文字列のハッシュのシードが違うため、集合の走査順序が、実行の間で変わります。

カラム1つがどこから来たかを実験で測る

columnsを追加して、出力カラムごとに依存する入力カラムのソートされた一覧を出力させ、同じ内容を/root/lineage/columns.jsonに残してください。

書いておくだけで終わらせず、実験で確認してください。入力カラム1つを揺らしてもう一度回し、どの出力カラムが変わるかを見ます。店舗を変えると、出力の行そのものが変わるため、すべてのカラムがそこに依存します。伝票番号を、ほかの行と同じにすると、その行が重複として抜けるため、件数と数量と金額が一緒に動きます。集計がまったく読まないカラムは、どこにも出てこない必要があります。

マニフェストどおりに作り直して突き合わせる

verify <매니페스트>(プレースホルダーはマニフェストです)を追加して、入力ハッシュとコードのハッシュを現在の値と比べ、マニフェストの入力とパラメーターで作り直して、出力のハッシュを突き合わせさせてください。1つでもずれれば、終了コード4です。

入力は、なくなったものと、内容が変わったものを分けて報告してください。調査する人にとっては、別の話だからです。マニフェストに書かれたパラメーターで、もう一度回す必要があります。今のデフォルト値で回すと、そのときと違う答えが出ても、原因を指摘できません。

その数字がどの入力から来たかに答える

trace --manifest <파일> --key <상호>(プレースホルダーは、ファイルと店舗です)を追加して、その店舗の件数と数量と金額、そして行を実際に足した入力ファイルを、名前とコンテンツハッシュと行数で出力させてください。そして、/root/lineage/lineage_report.mdに、## 이 숫자는 어디서 왔나、## 이름과 시각은 왜 근거가 못 되나、## 두 번 돌려 같았는가、## 칼럼 하나가 어디서 왔나の4つの節で書いてください(韓国語の見出しで、順に「この数字はどこから来たか」「名前と時刻はなぜ根拠にならないか」「2回回して同じだったか」「カラム1つがどこから来たか」を意味します)。

sourcesには、その店舗の行を実際に足したファイルだけを入れます。読みはしたものの、1行も足さなかったファイルは、リネージではありません。ハッシュは、マニフェストに書かれた値をそのまま使ってください。レポートには、数字を書いてください。調査する人が、自分のファイルでその行を開いて見られる必要があります。