EXP-007 / STATUS: ONLINE

CSV Diff— ブラウザだけでCSVの差分を比較する

行順が変わっただけなのか。値が変わったのか。
業務キーを指定して、新旧のCSVを比較する道具を作った。
00 — WHY

CSVを比べるだけ、が意外と面倒

システム開発やデータ移行、ETL、バッチ処理では、CSVを比較する場面がよくある。処理前後のデータを見たい時もあれば、新旧環境の出力が一致しているか確認したい時もある。

ファイル比較をかけると、大量の差分が出る。でも、よく見ると行順が違うだけだったりする。値が変わっていても、横に長いレコードから変更されたカラムを探すのは手間がかかる。

確認したいのは、同じ顧客や同じ明細について、何が増え、何が消え、何が変わったのかということだ。

そこで、業務キーを指定してレコード単位で比較するCSV Diffを作った。UTILIZABLEに追加した4つ目のツールになる。

サイト全体の構成と公開基盤はEXP-006に記録した。今回は、実際の比較で迷わず使えるようにするための設計を残しておく。

01 — INPUT

2つのCSVと、1つのキー

入力はBefore / Old CSVとAfter / New CSVの2つ。どちらもCSVファイルの選択とテキスト貼り付けに対応した。

Before・Afterそれぞれでファイルを選択すると、対応する貼り付け欄よりファイルを優先して読み込む。先頭行はヘッダーとして扱う。

読み込み後、左右に共通するカラム名から比較キーを選ぶ。初期版は単一キーに対応し、キーを選ぶまでは比較を実行できない。

例えば、次のCSVを比較する。

Before / Old CSV

ID,NAME,AMOUNT
1001,TANAKA,1000
1002,SUZUKI,2000
1003,SATO,3000

After / New CSV

ID,NAME,AMOUNT
1001,TANAKA TARO,1200
1002,SUZUKI,2000
1004,YAMADA,4000

比較キーにIDを指定すると、結果はこうなる。

Key: ID

Before rows: 3
After rows: 3
Added: 1
Removed: 1
Changed: 1
Unchanged: 1

1004が追加、1003が削除、1001が変更、1002は変更なし。この入力はページ内のExampleボタンでも試せる。

02 — CLASSIFICATION

行番号ではなく、キーで対応付ける

BeforeとAfterのレコードをキーで対応付け、4種類に分類する。

キーを基準にした比較結果
分類条件
AddedAfterにだけ存在する
RemovedBeforeにだけ存在する
Changed両方に存在するが、キー以外の値が異なる
Unchanged両方に存在し、値も同じ

行順が入れ替わっても、同じキーのレコードを比較する。カラムも名前で対応付けるため、列の並び順が違うだけなら差分にはならない。

キーと値は文字列として完全一致で比較する。前後の空白や大文字・小文字は区別し、数値らしい値も勝手に変換しない。例えば、コードの001と1は別の値として扱う。

03 — DUPLICATE KEYS

比較できない時は、止める

同じキーが複数あると、BeforeのどのレコードとAfterのどのレコードを比較するのかが曖昧になる。

先に見つかった行を採用すると、残りの行を見落とすかもしれない。並び順で組み合わせても、それが正しい対応とは限らない。

そのため、Before・Afterのどちらかでキー重複を検出した場合は、エラーを表示して比較を停止する。空のキーもエラーにした。

結果が出たように見えて、その対応付けが間違っている状態は避けたい。比較の前提が成立しない場合は、入力を確認してもらう設計にした。

04 — CHANGED COLUMNS

変わったカラムだけを見る

Changedでは、変更されたカラムとBefore / Afterの値を表示する。先ほどのID 1001なら、確認するのはこの2つだ。

ID: 1001 の変更内容
ColumnBeforeAfter
NAMETANAKATANAKA TARO
AMOUNT10001200

数十、数百のカラムがあるCSVでも、変更箇所から確認を始められるようにした。AddedにはAfterの行内容、RemovedにはBeforeの行内容を表示する。

片方にしかないカラムも比較対象にする。存在しないカラムと、存在するが空文字のカラムは区別する。

05 — CSV PARSING

CSVの読み方を揃える

CSVはカンマで分割すれば読める、というわけではない。ダブルクォートで囲まれた値には、カンマや改行が含まれることもある。

CSV Diffでは、既存のCSV Inspectorで使っているCSV解析処理を共有した。同じサイトの中で、ツールによってCSVの読み方が変わらないようにしている。

  • ヘッダーありCSV
  • ダブルクォートで囲まれた値と、二重引用符によるエスケープ
  • ダブルクォート内のカンマ・改行
  • 空文字
  • CRLF / LFの改行コード
  • UTF-8 / UTF-8 BOM

その上で、CSV Diffに必要な検証を追加した。空入力、空・重複ヘッダー、列数不一致、指定キーの欠落、CSV解析エラーを表示する。

先頭行がヘッダーかどうかを内容だけで確実に判定することはできない。入力にはカラム名の行を用意する。ヘッダーだけのCSVは、データ行数0として比較できる。

06 — WEB WORKER

画面操作を止めないために

CSVの読み込み・解析・比較はWeb Workerで実行する。データが大きくなった時も、できるだけ画面操作を固めないためだ。

ただし、ブラウザのメモリが無制限になるわけではない。初期版では、Before・Afterそれぞれの入力に上限を設けた。

CSV DIFF / INPUT LIMITS
SIZE
1ファイル 20 MiB(貼り付け入力も同じ上限)
ROWS
最大 100,000データ行(ヘッダーを除く)
COLUMNS
最大 200列

差分の一覧も25件単位で表示する。Unchangedは件数だけにして、大量の変更なしレコードを画面に並べない。

入力を編集した時は、以前のキー選択と比較結果を無効にする。新しい入力を見ながら、古い結果を使ってしまうことも防ぎたかった。

07 — PRIVACY

CSVの内容は、ブラウザ内で扱う

UTILIZABLEの基本方針はBrowser-first。業務データを扱う道具なので、CSVの内容をMidnight Benchのサーバ、外部API、AIサービスへ送信せず、ブラウザ内で処理する。

利用状況の把握にはCloudflare Web Analyticsを使っている。ただし、ツールに入力したCSV内容をAnalyticsへ送信する設計にはしていない。

ページ閲覧に伴う通常のアクセス情報と、比較するCSVの内容は別のものとして扱う。この方針はPrivacyページにも記載した。

入力データはCookie、localStorage、IndexedDBにも保存しない。比較結果を持ち出す時は、利用者がCopyやDownloadを操作する。

08 — OUTPUT

確認した差分を、次の作業へ渡す

画面での確認と、その後の作業の両方を考えて、次の操作を用意した。

  • Summary:Before / Afterの行数と4分類の件数
  • All Changes / Added / Removed / Changedのフィルタ
  • 25件単位の一覧表示
  • Copy summary:件数をクリップボードへコピー
  • Download diff CSV:全差分をCSVとしてダウンロード
  • Reset / Clear:入力・選択キー・比較結果を初期化
  • Example:この記事のサンプルを入力

Download diff CSVは、表示中のフィルタに関係なく全差分を出力する。STATUS、KEY、COLUMN、BEFORE、AFTERに加え、値の存在有無を示すBEFORE_PRESENT、AFTER_PRESENTを持たせた。Added / Removedも1カラム1行で記録する。

ファイルはUTF-8 BOM付き。表計算ソフト向けの数式対策は初期状態でONにし、数式として解釈され得る先頭文字を持つ値にシングルクォートを付ける。元の値のまま出力したい場合はOFFにできる。

差分を確認して終わるだけでなく、調査メモや後続のチェックへ渡せるようにした。Resetは、ダウンロード済みのファイルやコピー済みの内容までは消去しない。

09 — TESTS

小さな比較でも、境界を確認する

CSV Diff用に13件のテストを追加し、既存の4件と合わせて17件が成功した。

Added、Removed、Changed、Unchangedの分類に加えて、キー重複、キー未指定・欠落、quoted CSV、空文字、列順の違いなどを確認した。

ダブルクォート内のカンマや改行、差分CSV出力時のエスケープ、存在しない列と空文字の区別も対象にしている。サンプルでは4分類が各1件になることを確認した。

ブラウザ上でも、ファイルの読み込み、フィルタ、出力、ページ切り替え、Reset、スマートフォン幅での表示を確認した。

業務の確認に使うなら、まず基本の対応付けが崩れないことが大事になる。CSV解析の共通処理を変更せず、既存ツールのテストも通る状態にした。

10 — NEXT

道具が4つになった

UTILIZABLEの現在のツールは、この4つ。

  • 01 — SQL Formatter
  • 02 — SQL IN Generator
  • 03 — CSV Inspector
  • 04 — CSV Diff

次に何を作るかは、まだ決めていない。データエンジニアリングの現場で繰り返す、小さいけれど面倒な作業から選んでいく。

CSV Diffも実際に使いながら、比較しづらいケースや操作の引っかかりを直していきたい。

CSV Diffを試す →
UTILIZABLEのツール一覧 →

Make data usable.
毎回のひと手間を、道具にする。