巨大な区切りテキストファイルから列を抽出する

巨大な区切りテキストファイルから列を抽出する

33GBのパイプで区切られたフラットファイルがあります。

最初の列と20番目の列が条件を満たすファイルから特定の列を抽出する必要があります。

次のコードを使用して入力ファイルを処理します。

awk -F"|" '('$1~/^BL|^FR|^GF|^GP|^MC|^MF|^MQ|^NC|^PF|^PM|^RE|^TF|^WF|^YT/&&$20=="TRUE"') {print $0}' <input file> | cut -d'|' -f1-3,6,10,11,13,19,20 >> <output file>

$1$20入力ファイルの列位置です。

このコードはうまく動作します。ただし、データの抽出には約1.5時間かかります。ファイルをより迅速に処理する方法はありますか?

答え1

を試してくださいgrep

(
  export LC_ALL=C
  grep -E '^(BL|FR|[GMTW]F|GP|M[CQ]|NC|PM|RE|YT)([^|]*\|){19}TRUE(\||$)' |
    cut -d'|' -f1-3,6,10,11,13,19,20
)

@don_crisstiが提案したように、すべての行に20個以上のフィールドが含まれていると仮定すると、最初に切り取りを試みることもできます。これにより、各行のフィールド数と長さ、一致する行の割合に基づいてパフォーマンスが向上します。

(
  export LC_ALL=C
  cut -d'|' -f1-3,6,10,11,13,19,20 |
    grep -xE '(BL|FR|[GMTW]F|GP|M[CQ]|NC|PM|RE|YT).*\|TRUE'
)

答え2

マークしてみますか?バージョン1.34以降を使用してください。一部の人の例では、大容量ファイルを処理する作業が8倍速くなる可能性があります。

https://brenocon.com/blog/2009/09/dont-mawk-awk-the-fastest-and-most-elegant-big-data-munging-言語/

現在のパフォーマンスと絶対的な比較のために、これは1GBを処理するのに1分(mawkを使用)かかりました。 Java(JIT)コードを使用しようとする試みは速くありません。

また、UTF-8のサポートが追加された後、多くのユーティリティのパフォーマンスが低下したようです。 ㅏGoogle検索これは、少なくともいくつかのバージョンのawkに非常に顕著な影響を与えることを示しています。環境変数LC_ALL=C(例LC_ALL=C awk ...:)を使用して実行してみてください。

答え3

少なくとも以下を削除できますcut

awk -F '|' 'BEGIN { OFS=FS } $20 == "TRUE" && /^(BL|FR|GF|GP|MC|MF|MQ|NC|PF|PM|RE|TF|WF|YT)/ { print $1,$2,$3,$6,$10,$11,$13,$19,$20 }' indata >outdata

これがより速く実行されるかどうかはわかりませんが、各行をフィールドに複数回分割する必要はありません。

awkフィルタリングの労力を減らすために、最初に正しい列を削除してみることもできます。

cut -d '|' -f 'columnspec' indata | awk -F '|' 'BEGIN { OFS=FS } $20 == "TRUE" && /^(BL|FR|GF|GP|MC|MF|MQ|NC|PF|PM|RE|TF|WF|YT)/ { print }' >outdata

別のアプローチは、ファイルを管理可能なチャンクに分割し、チャンクを並列にフィルタリングしてから結果をリンクすることです。splitUnixのマニュアルを参照してください。何百ものファイルを作成する場合は、分割フラグを使用する必要がありますが、-aデータ内のファイルの行数を数えて約10個のファイルに分割することをお勧めします。

答え4

Pythonの行別アプローチの使用

次のスクリプトは、最初の列が定義された文字列と同じ場合、行のすべての列セットを返します。必須一致と返される列は、スクリプトを実行するためのパラメータです。一例:

python3 /path/to/script.py /path/to/file.txt monkey 3 12 > output.txt

最初の列が「monkey」と等しい場合、file.txtの各行の列0、2、11が返されます(最初の列は0です)。

タイミング

30,000,000行の数ギガバイトファイルでは、スクリプトは10年以上前のマイコンピュータから1分以内に作業を完了しました。スクリプトが読み取られ処理されるため各ライン、消費される時間がやや直線的であり、スクリプトがコマンドよりもはるかに速くタスクを実行すると仮定できます。

スクリプト

#!/usr/bin/env python3
import sys

s = sys.argv[2]; cols = [int(n) for n in sys.argv[3:]]

with open(sys.argv[1]) as src:
    for l in src:
        l = l.split("|"); match = l[0].strip()
        if match == s:
            print(match, " ".join(list(l[i].strip() for i in cols)))

使い方

  1. スクリプトを空のファイルにコピーして別の名前で保存します。get_cols.py
  2. 次のパラメータを使用して実行します。

    • ソースファイル
    • 最初の列(文字列)の必須一致
    • 出力する列

    たとえば、

    python3 /path/to/get_cols.py Germany 2 12 > output.txt
    

それだけです。

関連情報