はじめに
集計はRDBばかりに頑張らせるのをやめると幸せになれる。のですが、JOINコマンドを利用するともっと幸せになれます。
JOINコマンドとは
こちらに詳しくまとまっているのですが、2つのtsvファイルや、csvファイルをjoinする事ができます。
RDBを利用できない時に、ファイルだけでテーブル間の結合処理ができるという夢のようなコマンドですが、sortとの兼ね合いで思ったようにjoin出来ないことがあります。
結論から言うと
join: [ファイル]: is not sorted:
というエラーが出たときには、
- join前のsort時にLANG=Cを指定する。
- join時にもLANG=Cを指定する。
JOINが失敗するなら、grepで似たようなこと出来ないの?
近いことで、以下のコマンドで、[ファイル2]中にある[ファイル1]の内容を含む行を抽出することができますが、これは計算量のオーダーが[ファイル1のサイズ] * [ファイル2のサイズ]であるため、これが巨大なときには何時まで待っても完了しません。
grep -f [ファイル1] [ファイル2]
ファイル1が100万行,ファイル2が1000万行だったときには計算量のオーダーは10兆回です。
JOINコマンドは速い
JOINコマンドを利用するためには、予め[ファイル1]と[ファイル2]が適切にソートされている必要がありますが、その分高速に動作します。
ソート済みのファイル同士を上から比較することで、[ファイル1のサイズ]+[ファイル2のサイズ]のオーダーの計算量で比較を行ないます。
ファイル1が100万行,ファイル2が1000万行だったときには計算量のオーダーは1100万回で、grepを利用するケースのおよそ91万分の1です。
sort [ファイル1] > [ソート済みファイル1]
sort [ファイル2] > [ソート済みファイル2]
SORTの際に気をつけなければならないこと
sortコマンドは環境変数により、文字列のスコア評価が変わり、ソート順が変更されてしまいます。
例:
- 大文字小文字を無視する。
- 数値以外を無視する。
- "-"ハイフンや"+"プラスなどを無視する
- etc...
sort時の文字列スコア評価とjoin時の文字列スコア評価が異なるとjoinコマンドは
join: [ファイル1]: is not sorted:
というエラーを吐き、処理を中断してしまいます。
ここで、sortの結果を固定するために、LANG=Cを指定して下さい。
LANG=C sort [ファイル1] > [ソート済みファイル1]
LANG=C sort [ファイル2] > [ソート済みファイル2]
JOINの際に気をつけなければならないこと
sortと同様に、joinコマンドも環境変数により文字列のスコア評価が変わりますので、環境によってはこちらも適切に指定してあげないとjoin出来ません。
sort時に指定したのと同じLANGを指定してjoinします。
LANG=C join [ソート済みファイル1] [ソート済みファイル2] [オプション]