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

データパイプライン

隔離を運用する — 積み、止め、戻す

TT Labで続きを見る

目標

期待値をファイルに書いておき、ドロップを実行ごとに行単位でふるいにかけて、sqliteのファクトテーブルと隔離テーブルに分けて積むゲートキーパーqgate.pyを作ります。間違いが多すぎる実行は丸ごと止め、直した行を入れ直しても二重計上が起きないようにし、古くなった隔離を見つけ出し、実行の状態とデータの状態を分けて報告します。

なぜ重要なのか

使えない行を捨てずに隔離に残すところまでは、たいていやります。問題は、その次です。隔離は、実行のたびにまた積み重なり、半年後に開いてみると4万行が入っていて、その間、集計はその分が抜けたまま出ていました。パイプラインは毎日成功しました。成功とは、エラーなしに終わったという意味であって、入れるべきものをすべて入れたという意味ではありません。行1つが間違っていることと、ファイル全体が間違っていることも、別の出来事です。上流がカラムの順序を変えて送ると、ほぼすべての行がずれますが、そのときに行単位で隔離すると、隔離テーブルに1万行が入り、集計は空のまま出ていきます。そのようなファイルは、1行も入れずに、実行を止めるほうがよいです。分ける基準は比率で、その比率は、きりのいい数ではなく、普段の失敗率から決めます。そして、直した行を入れ直すループが必要です。再投入は、人が手で回す作業なので、必ず何回も実行され、そのときに、ファクトテーブルに2回入ったり、すでに閉じた隔離をまた閉じて、「3件解決」が2回報告されたりしやすくなります。採点ツールは、提出された文言を信じません。一時ディレクトリに、採点ツールが作ったドロップと期待値を用意して、自分で作ったゲートキーパーを実際に実行したあと、作られたsqliteファイルを直接開いて、ファクトと隔離と実行記録を、採点ツールが直接数えた値と突き合わせます。しきい値と店舗と金額は、実行ごとに変わります。

ステップ

  1. /root/quarantine/gen_drops.pyを作成して実行し、/root/quarantine/dropsの下にドロップ4つと、/root/quarantine/expectations.jsonを作ってください。
  2. /root/quarantine/qgate.pyにcheckを作り、期待値で数えるだけにしてください。
  3. runを追加して、sqliteにファクトと隔離と実行記録を積ませてください。
  4. run --max-fail-ratioを追加して、間違いが多すぎる実行を丸ごと止めさせてください。
  5. requeueを追加して、直した行を入れ直しても、2回入れても数字が変わらないようにしてください。
  6. agingを追加して、古くなった隔離を見つけ出させてください。
  7. statusを追加して、実行の状態とデータの状態を分けて報告させてください。
  8. 自分のドロップ4つを順番に回して/root/quarantine/pipeline.dbを作り、/root/quarantine/status.jsonと/root/quarantine/quarantine_report.mdを書いてください。

参考

ドロップと期待値をファイルとして置く

/root/quarantine/gen_drops.pyを作成して実行し、/root/quarantine/dropsの下にドロップ4つと、/root/quarantine/expectations.jsonを作ってください。期待値は、5種類のtypeをすべて使い、ドロップの1つは、半分を超えて期待値を破っている必要があります。

期待値をコードではなくファイルに置けば、上流とそのファイルを見ながら話せて、破られたルールの名前が、そのまま隔離の理由になります。ドロップには、ステータスの値が一覧にない行、負の金額、範囲を超える数量、空の店舗、規格を守っていない伝票番号、前の行と同じ伝票番号を混ぜてください。3つは、破る行が半分未満で、1つは半分を超える必要があります。

期待値で数えるだけにする

/root/quarantine/qgate.pyにcheck --drop <파일> --expect <파일>(プレースホルダーは、ファイルです)を作り、drop・rows・passed・failed・fail_ratio・by_ruleをJSONで出力させてください。

failedは、1つ以上のルールを破った行の数で、by_ruleはルールごとに破った行の数なので、合計が違います。1つの行が2つのルールを破ることがあるからです。by_ruleには、誰も破らなかったルールも、0として入れてください。値が空なら、not_null以外はすべて失敗と見なします。

ファクトと隔離を分けて積む

run --drop <파일> --db <파일> --expect <파일>(プレースホルダーは、ファイルです)を追加して、通過した行はfactsに更新として入れ、破った行は、破ったルールごとにquarantineに開き、実行をrunsに残させてください。同じ行の同じ理由がまた来ても、隔離は1回だけ開きます。

3つの表のカラム名と順序は、参考の節にあります。ファクトテーブルは、order_idが主キーなので、更新として入れます。隔離を開く前に、同じorder_idとruleで、まだ開いている行があるかを見てください。見なければ、実行のたびに同じ行が積み重なります。

間違いが多すぎる実行は丸ごと止める

run --max-fail-ratio R(プレースホルダーは比率です)を追加して、fail_ratioがしきい値を超えたら、実行を止めるようにしてください。止まった実行は、runsにbrokenとして残し、ファクトも隔離も1行も入れず、終了コードは5です。

行1つが間違っていることと、ファイル全体が間違っていることは、別の出来事です。しきい値は、きりのいい数ではなく、普段の失敗率から決めます。checkでドロップ4つの比率を測ってみてから決めてください。止めるときに、半分だけ入れて止まると、次の人がどこまで入ったかを判断する必要があります。

直した行を入れ直す

requeue --db <파일> --fixes <파일> --expect <파일>(プレースホルダーは、ファイルです)を追加して、直した行を期待値でもう一度見て、通過すればファクトテーブルに更新として入れ、その伝票のまだ開いている隔離だけを閉じるようにしてください。同じ再投入を2回実行しても、ファクトの件数と閉じた隔離の数が、増えない必要があります。

再投入は、人が手で回す作業なので、必ず何回も実行されます。挿入で入れるとファクトが2倍になり、閉じるときに「開いている」条件をかけないと、「3件解決」が2回報告されます。2回目の実行のresolvedは、0である必要があります。伝票番号そのものが壊れた行は、再投入では直せません。番号を直すと、別の行になるからです。

古くなった隔離を見つけ出す

aging --db <파일> [--max-age-runs N](プレースホルダーは、ファイルです)を追加して、開いている隔離の古さをlatest_run_id - first_run_idで測り、max_age_runs以上のものを数えて、open・aged・by_rule・oldest・alertで出力させてください。

件数だけを見ても、減らないものを見られません。古さは、時刻よりも実行回数で測るほうが扱いやすいです。パイプラインが回らなければ、古さも増えないほうが、人の感覚に合っています。oldestは、開いているもののうち、first_run_idが最も小さいものです。

成功したことと正しいことを分けて報告する

status --db <파일> [--max-age-runs N](プレースホルダーは、ファイルです)を追加して、実行の状態(runs)とデータの状態(data)を分けて出力し、runs_ok・data_okの2つの値で答えさせてください。

実行が成功したことと、データが正しいことは、別の軸です。1つの欄にまとめると、どちらも見えなくなります。runs_okは、実行があり、最後の実行が止まっていないかで、data_okは、開いている隔離と、古くなった隔離が、どちらも0かです。両方が真の日は、まれです。

自分のドロップで1週間分を回して報告する

自分のドロップ4つを日付順に回して/root/quarantine/pipeline.dbを作り、statusの答えを/root/quarantine/status.jsonに残し、/root/quarantine/quarantine_report.mdを4つの節で書いてください。停止のしきい値は、普段の失敗率を測って決めてください。

しきい値を普段の値から決めれば、半分を超えて破ったその日の分だけが止まります。status.jsonは、手で書かず、statusコマンドの答えをそのまま保存してください。採点ツールは、データベースを直接開いて突き合わせます。レポートには、ファクトの件数と開いている隔離の件数を、数字で書いてください。