2016-01-25 7 views
6

私は、コマンドを実行するためのシェルコマンドを優先しています。私は非常に大きなファイルを持っています - 約2.8 GB、その内容はJSONのものです。すべてが1行にあり、少なくとも150万レコードがそこにあると言われました。非常に大きなファイル内の文字列を検索して置き換えます

私は消費のためにファイルを準備する必要があります。各レコードはそれぞれの行になければなりません。サンプル:使用する次の

{"RomanCharacters":{"Alphabet":[{"RecordId":"1",...]},{"RecordId":"2",...},{"RecordId":"3",...},{"RecordId":"4",...},{"RecordId":"5",...} }} 

それとも、...

{"Accounts":{"Customer":[{"AccountHolderId":"9c585258-c94c-442b-a2f0-1ebbcc274795","Title":"Mrs","Forename":"Tina","Surname":"Wright","DateofBirth":"1988-01-01","Contact":[{"Contact_Info":"9168777943","TypeId":"Mobile Number","PrimaryFlag":"No","Index":"1","Superseded":"No" },{"Contact_Info":"9503588153","TypeId":"Home Telephone","PrimaryFlag":"Yes","Index":"2","Superseded":"Yes" },{"Contact_Info":"[email protected]","TypeId":"Email Address","PrimaryFlag":"No","Index":"3","Superseded":"No" },{"Contact_Info":"[email protected]","TypeId":"Email Address","PrimaryFlag":"Yes","Index":"4","Superseded":"Yes" }, {"Contact_Info":"[email protected]","TypeId":"Email Address","PrimaryFlag":"No","Index":"5","Superseded":"NO" },{"Contact_Info":"15482475584","TypeId":"Mobile_Phone","PrimaryFlag":"No","Index":"6","Superseded":"No" }],"Address":[{"AddressPtr":"5","Line1":"Flat No.14","Line2":"Surya Estate","Line3":"Baner","Line4":"Pune ","Line5":"new","Addres_City":"pune","Country":"India","PostCode":"AB100KP","PrimaryFlag":"No","Superseded":"No"},{"AddressPtr":"6","Line1":"A-602","Line2":"Viva Vadegiri","Line3":"Virar","Line4":"new","Line5":"banglow","Addres_City":"Mumbai","Country":"India","PostCode":"AB10V6T","PrimaryFlag":"Yes","Superseded":"Yes"}],"Account":[{"Field_A":"6884133655531279","Field_B":"887.07","Field_C":"A Loan Product",...,"FieldY_":"2015-09-18","Field_Z":"24275627"}]},{"AccountHolderId":"92a5788f-cd8f-423d-ae5f-4eb0ceb457fd","_Title":"Dr","_Forename":"Christopher","_Surname":"Carroll","_DateofBirth":"1977-02-02","Contact":[{"Contact_Info":"9168777943","TypeId":"Mobile Number","PrimaryFlag":"No","Index":"7","Superseded":"No" },{"Contact_Info":"9503588153","TypeId":"Home Telephone","PrimaryFlag":"Yes","Index":"8","Superseded":"Yes" },{"Contact_Info":"[email protected]","TypeId":"Email Address","PrimaryFlag":"No","Index":"9","Superseded":"No" },{"Contact_Info":"[email protected]","TypeId":"Email Address","PrimaryFlag":"Yes","Index":"10","Superseded":"Yes" }],"Address":[{"AddressPtr":"11","Line1":"Flat No.14","Line2":"Surya Estate","Line3":"Baner","Line4":"Pune ","Line5":"new","Addres_City":"pune","Country":"India","PostCode":"AB11TXF","PrimaryFlag":"No","Superseded":"No"},{"AddressPtr":"12","Line1":"A-602","Line2":"Viva Vadegiri","Line3":"Virar","Line4":"new","Line5":"banglow","Addres_City":"Mumbai","Country":"India","PostCode":"AB11O8W","PrimaryFlag":"Yes","Superseded":"Yes"}],"Account":[{"Field_A":"4121879819185553","Field_B":"887.07","Field_C":"A Loan Product",...,"Field_X":"2015-09-18","Field_Z":"25679434"}]},{"AccountHolderId":"4aa10284-d9aa-4dc0-9652-70f01d22b19e","_Title":"Dr","_Forename":"Cheryl","_Surname":"Ortiz","_DateofBirth":"1977-03-03","Contact":[{"Contact_Info":"9168777943","TypeId":"Mobile Number","PrimaryFlag":"No","Index":"13","Superseded":"No" },{"Contact_Info":"9503588153","TypeId":"Home Telephone","PrimaryFlag":"Yes","Index":"14","Superseded":"Yes" },{"Contact_Info":"[email protected]","TypeId":"Email Address","PrimaryFlag":"No","Index":"15","Superseded":"No" },{"Contact_Info":"[email protected]","TypeId":"Email Address","PrimaryFlag":"Yes","Index":"16","Superseded":"Yes" }],"Address":[{"AddressPtr":"17","Line1":"Flat No.14","Line2":"Surya Estate","Line3":"Baner","Line4":"Pune ","Line5":"new","Addres_City":"pune","Country":"India","PostCode":"AB12SQR","PrimaryFlag":"No","Superseded":"No"},{"AddressPtr":"18","Line1":"A-602","Line2":"Viva Vadegiri","Line3":"Virar","Line4":"new","Line5":"banglow","Addres_City":"Mumbai","Country":"India","PostCode":"AB12BAQ","PrimaryFlag":"Yes","Superseded":"Yes"}],"Account":[{"Field_A":"3288214945919484","Field_B":"887.07","Field_C":"A Loan Product",...,"Field_Y":"2015-09-18","Field_Z":"66264768"}]}]}} 

最終的な結果は次のようになります。

{"RomanCharacters":{"Alphabet":[{"RecordId":"1",...]}, 
{"RecordId":"2",...}, 
{"RecordId":"3",...}, 
{"RecordId":"4",...}, 
{"RecordId":"5",...} }} 

未遂コマンド:

  • sed -e 's/,{"RecordId"/}]},\n{"RecordId"/g' sample.dat
  • awk '{gsub(",{\"RecordId\"",",\n{\"RecordId\"",$0); print $0}' sample.dat

試行されたコマンドは、小さなファイルに対して完全に正常に動作します。しかし、それは私が操作しなければならない2.8GBのファイルでは機能しません。セドは理由なく10分後に途中で止まり、何もしなかった。数時間後にセグメンテーションフォールト(コアダンプ)の理由でエラーが発生しました。私はperlの検索と置換を試み、「メモリ不足」と言っているエラーを受けました。

どのようなヘルプやアイデアも素晴らしいでしょう。私のマシンで

追加情報:利用可能

  • 以上105ギガバイトのディスクスペース。
  • 8ギガバイトのメモリ
  • 4コアのUbuntu 14.04
+0

サンプルデータが必要です。データをダンプする必要はありませんが、手元の問題点を説明してください。また、パーサの使用を検討しましたか? – Sobrique

+1

基本的な問題は、私が思うには、これらのツールの3つすべてが一度に1行ずつ読み込まれ、「単一の巨大な線」に覆われてしまうことです。コンマを改行で置き換えるには、まず 'tr '、' '\ 012' 'のようなもので前処理をしてください。それで、一度に一本線のツールがうまくいくでしょう。 –

+0

perlでもう一度やり直してくださいが、$ /を "、"に設定してください。また、sed(--unbuffered)の "-u"パラメータも試してください。 – neuhaus

答えて

3

#!/usr/bin/perl 
$/= "},"; 
while (<>){ 
    print "$_\n"; 
}' 
:このよう },に入力行区切り $/を設定してみてください

または、ワンライナーとして:

$ perl -e '$/="},";while(<>){print "$_\n"}' sample.dat 
+1

これは迅速に動作することが証明されています。私はあなたのスクリプトを修正して問題の解決策を見つけました。私はすぐにそれを共有します。 – dat789

+0

'-n'と' -p'フラグを見てみる価値があります。 'perl -pe 'BEGIN {$/="}、 "}" \ n "を出力してください。 } ' – Sobrique

2

例えば、レコードセパレータとして}を使用してみてくださいを実行するCPU

  • Perlで:

    perl -l -0175 -ne 'print $_, $/' < input 
    

    あなただけ}を含む行をバック接着する必要がある場合があります。

  • 2

    これは、単一のレコードとしてデータを参照しないことによってメモリの問題を回避しますが、パフォーマンス(1つの文字を一度に処理する)に関してあまりにも大きくなる可能性があります。あなたはSED、AWKやPerlとあなたの質問をタグ付けしましたので、私はあなたが本当に何が必要であることを集める

    $ cat j.awk 
    BEGIN { RS="[[:print:]]" } 
    RT == "{" { bal++} 
    RT == "}" { bal-- } 
    { printf "%s", RT } 
    RT == "," && bal == 2 { print "" } 
    END { print "" } 
    
    $ gawk -f j.awk j.txt 
    {"RomanCharacters":{"Alphabet":[{"RecordId":"1",...]}, 
    {"RecordId":"2",...}, 
    {"RecordId":"3",...}, 
    {"RecordId":"4",...}, 
    {"RecordId":"5",...} }} 
    
    4

    :またそれは、内蔵RT変数(現在のレコードセパレータの値)のためのgawk必要とすることに注意してくださいツールの推奨事項です。これは話題にはなりませんが、私はjqがこれに使用できると信じています。実際にがJSONを理解しているので、sedまたはawkよりも優れています。ここにjqで示されているものはすべて、少しのプログラミングでperlで行うこともできます。

    {"RomanCharacters":{"Alphabet": [ {"RecordId":"1","data":"data"},{"RecordId":"2","data":"data"},{"RecordId":"3","data":"data"},{"RecordId":"4","data":"data"},{"RecordId":"5","data":"data"} ] }} 
    

    あなたは簡単にそれを「飾り立てる」ために、これを再フォーマットすることができます:

    $ jq '.' < data.json 
    { 
        "RomanCharacters": { 
        "Alphabet": [ 
         { 
         "RecordId": "1", 
         "data": "data" 
         }, 
         { 
         "RecordId": "2", 
         "data": "data" 
         }, 
         { 
         "RecordId": "3", 
         "data": "data" 
         }, 
         { 
         "RecordId": "4", 
         "data": "data" 
         }, 
         { 
         "RecordId": "5", 
         "data": "data" 
         } 
        ] 
        } 
    } 
    

    をそして、我々はデータに掘ることができます(あなたのサンプルに基づいて)次のような内容を想定し

    興味のあるレコードのみを検索します(ラップされた内容に関係なく)。

    $ jq '.[][][]' < data.json 
    { 
        "RecordId": "1", 
        "data": "data" 
    } 
    { 
        "RecordId": "2", 
        "data": "data" 
    } 
    { 
        "RecordId": "3", 
        "data": "data" 
    } 
    { 
        "RecordId": "4", 
        "data": "data" 
    } 
    { 
        "RecordId": "5", 
        "data": "data" 
    } 
    

    人間とawkのようなツールの両方で、内容を行ごとに処理することにより、はるかに読みやすくなります。あなたの質問当たりの処理のためのあなたのラインに参加したい場合は、awkがはるかに簡単になる:

    $ jq '.[][][]' < data.json | awk '{printf("%s ",$0)} /}/{printf("\n")}' 
    { "RecordId": "1", "data": "data" } 
    { "RecordId": "2", "data": "data" } 
    { "RecordId": "3", "data": "data" } 
    { "RecordId": "4", "data": "data" } 
    { "RecordId": "5", "data": "data" } 
    

    あるいは、@peakはコメントで示唆されているように、完全JQの-c(コンパクト出力を使用することにより、チエニルのawk部分を排除)オプション:perlのについて

    $ jq -c '.[][][]' < data.json 
    {"RecordId":"1","data":"data"} 
    {"RecordId":"2","data":"data"} 
    {"RecordId":"3","data":"data"} 
    {"RecordId":"4","data":"data"} 
    {"RecordId":"5","data":"data"} 
    
    +0

    ここでは、jqの-cオプションを使用することができます。 data.jsonを使用する例では、 'jq -c '。[] [] []' peak

    +0

    @peak - 華麗な、私には決して起こらなかった何らかの理由で、ありがとう。 :-)私はそれを私の答えに加えました。 – ghoti

    0

    ここで提供されるサンプルデータを使用して({アカウントから始まる1:{顧客...)、この問題に対する解決策を読み込むものです$ /に定義されている区切り文字の数を数えています。 10,000個の区切り文字ごとに、新しいファイルに書き出します。見つかった区切り文字ごとに新しい行が付けられます。私はそれがコンテンツは書式なしのワンライナーJSONでのビッグ2.8ギガバイトのファイルに対して、このスクリプトを使用しました

    #!/usr/bin/perl 
    
    $base="/home/dat789/incoming"; 
    #$_="sample.dat"; 
    
    $/= "}]},"; # delimiter to find and insert new line after 
    $n = 0; 
    $match=""; 
    $filecount=0; 
    $recsPerFile=10000; # set number of records in a file 
    
    print "Processing " . $_ ."\n"; 
    
    while (<>){ 
        if ($n < $recsPerFile) { 
         $match=$match.$_."\n"; 
         $n++; 
         print "."; #This is so that we'd know it has done something 
        }  
        else { 
         my $newfile="partfile".$recsPerFile."-".$filecount . ".dat"; 
         open (OUTPUT,'>', $newfile); 
         print OUTPUT $match; 
         $match=""; 
         $filecount++; 
         $n=0; 
        print "Wrote file " . $newfile . "\n"; 
        } 
    } 
    
    print "Finished\n\n"; 
    

    :ここではスクリプトがどのように見えるかです。結果の出力ファイルには正しいJSONヘッダーとフッターが表示されませんが、これは簡単に修正できます。

    寄付いただきありがとうございます!

    関連する問題