順序を乱すことなく複数のフィールドを持つCSVに参加

順序を乱すことなく複数のフィールドを持つCSVに参加

2つのCSVファイルがあります。最初のファイルはサイズが大きく(400を超えるフィールド、多くの行が100万を超える)、一致結合を介して別のフィールドを追加する必要があります。

私はフィールドに参加したいと思います$170

頑張りました

gawk 'BEGIN {OFS=FS=","} NR==FNR{b[$1]=$2; next} 
$170 in b {print $0,b[$170]}
' b a

レポートによると、この方法はうまく機能しますが、ファイルサイズが大きくなると問題が発生する可能性があります。 この awk コマンドが完全な外部結合を実行しないのはなぜですか?(@cuonglmの回答を参照)

まだテストしていませんが、ファイルサイズが増えるにつれて、「最良の」アプローチを知りたいです。

@cuonglmが提案しましたが、joinこれは最初にリンクされたフィールドを配置するように列を並べ替えます。
非常に長いため、引数を使用してコマンドの長い出力形式を簡単に作成することはできません。join-o

join -1 170 -2 1 -o1.1 1.2 1.3 1.4......1.300.... file1 file2

joinこれをより簡単に行う方法はありますか?

gawkそれとも、ファイルサイズの問題のためにこれに固執する必要があります(たとえば、ファイルaとbに最大500万行があり、両方とも約500列があります)。

ベストアンサー1

完全なNordテストをしてみました。 500万行×500列(20GB)のCSVと500万行×2列の補助ファイルを作成しました。キーフィールドは一意であり(500万の素数があります)、ビッグファイルの列170とサイドファイルの列1にあります。両方のファイルには、独立してランダムに抽出されたキーシーケンスが含まれています。他のすべてのフィールドには、約14,000語(マンページから抽出)からランダムに選択された項目が含まれています。

awkスクリプトはほぼ20分間実行されました。全体のプロセスは約0.8GBのメモリを使用します。。これは4GBのノートパソコンと5400rpmのハードドライブにあります。ログには、時間、ファイルサイズ、列数が表示されます。

Paul--) time ./datMerge

real    18m31.740s
user    10m21.632s
sys 1m48.316s
Paul--) wc -lc *max*
    5061456 20045559105 FileA.max.csv
    5061456    85634275 FileB.max.csv
    5061456 20085640276 FileC.max.csv
   15184368 40216833656 total
Paul--) for f in F*max*; do
> awk '-F,' '{ printf ("%8d %s\n", NF, FILENAME); }' "${f}"
> done | uniq -c
5061456      500 FileA.max.csv
5061456        2 FileB.max.csv
5061456      501 FileC.max.csv
Paul--) ls -l F*max*
-rw-r--r-- 1 paul paul 20045559105 Feb  8 19:49 FileA.max.csv
-rw-r--r-- 1 paul paul    85634275 Feb  8 19:49 FileB.max.csv
-rw-r--r-- 1 paul paul 20085640276 Feb  8 20:24 FileC.max.csv
Paul--) 

私は6行と6列の機能を示すためにファイルのミニバージョンを作成しました。キーは4列にあります。

Paul--) head F*mini*
==> FileA.mini.csv <==
rather,complies,finite,99999847,AM,Or
elapsed,plied,nearperfect,99999989,pr,WinChip
phiopt,reflects,bottom,99999959,128N,careful
fpackstructn,realworld,msingleexit,99999931,0xffff,maxmimum
simplified,mpopcntb,FrontCover,99999971,523x,requisite
cede,fdumprtlbtl2,atmega649a,99999941,LC_MESSAGES,errno

==> FileB.mini.csv <==
99999847,symbols
99999931,fdumprtldbr
99999959,ambiguous
99999971,crc
99999989,munsafedma

==> FileC.mini.csv <==
rather,complies,finite,99999847,AM,Or,symbols
elapsed,plied,nearperfect,99999989,pr,WinChip,munsafedma
phiopt,reflects,bottom,99999959,128N,careful,ambiguous
fpackstructn,realworld,msingleexit,99999931,0xffff,maxmimum,fdumprtldbr
simplified,mpopcntb,FrontCover,99999971,523x,requisite,crc
cede,fdumprtlbtl2,atmega649a,99999941,LC_MESSAGES,errno,Default
Paul--) 

これがマージスクリプトです。データ生成スクリプトが有用な情報を提供したら、公開できます。

Paul--) cat datMerge
#! /bin/bash
#: datMerge

LC_ALL="C"

function Merge {

    local AWK='''
BEGIN { FS = ","; OFS = ","; K = 170; Null = "Default"; }
NR == FNR { htMap[$1] = $2; next; }
{ printf ("%s%s%s\n", $0, OFS, ($(K) in htMap) ? htMap[$(K)] : Null); }
'''
    awk "${AWK}" "${@}"
}

    Merge "FileB.max.csv" "FileA.max.csv" > "FileC.max.csv"

Paul--) 

おすすめ記事