2010-12-31 22 views
0

大きなデータセット(約90GB)を扱うことができます。毎日の時間ごとにデータファイル(タブ区切り)があり、データセット全体で操作を実行する必要があります。たとえば、列の1つに記載されているOSのシェアを取得します。私はすべてのファイルを1つの大きなファイルにマージして単純なカウント操作を実行しようとしましたが、サーバーメモリにとっては大きすぎます。Perlで一度に複数のファイルを解析する

だから、私は一度に各ファイルを操作し、最後に追加する必要があると思います。私はperlに慣れていないし、パフォーマンス上の問題については特に素朴です。このような場合にはどうすればいいですか?

例として、ファイルの2つの列があります。

ID  OS 
1  Windows 
2  Linux 
3  Windows 
4  Windows 

データセット内のOSのシェアを数えてみましょう。したがって、各.txtファイルには数百万の行があり、そのようなファイルが多数あります。ファイル全体を操作する最も効率的な方法は何でしょうか。

答えて

3

ファイル全体をメモリに読み込まない限り、ファイルのサイズが問題になる理由はわかりません。

my %osHash; 

while (<>) 
{ 
    my ($id, $os) = split("\t", $_); 
    if (!exists($osHash{$os})) 
    { 
     $osHash{$os} = 0; 
    } 
    $osHash{$os}++; 
} 

foreach my $key (sort(keys(%osHash))) 
{ 
    print "$key : ", $osHash{$key}, "\n"; 
} 
+2

値をインクリメントする前にキーが存在するかどうかを確認する必要はありません。それがまだ存在しない場合は、その場で作成されます。 – canavanin

+0

@canavanin、ゼロに初期化されますか?私はそれをテストしたことはありません。 –

+1

ソートキー%osHashに親が必要なこともありません。または、デフォルトでそれを使用するので、分割で$ _を使用することができます。また、キャメルケースはPerlersのかなり大きなサブセットを作るので、あなたはそれを避けたいかもしれません。 – Hugmeir

1

ハッシュを埋めるに対処ポールTomblinの答えは、ここで同じplusファイルを開くことですが:

use strict; 
use warnings; 
use 5.010; 
use autodie; 

my @files = map { "file$_.txt" } 1..10; 

my %os_count; 

for my $file (@files) { 
    open my $fh, '<', $file; 
    while (<$file>) { 
     my ($id, $os) = split /\t/; 
     ... #Do something with %os_count and $id/$os here. 
    } 
} 

私達はちょうど直列ファイルを開く - あなたはすべてのファイルからすべての行を読み取る必要があるので、あなたはそれについてもっと多くのことをすることはできません。ハッシュを作成したら、どこかに保存してプログラムが起動すると読み込み、最後に読まれるまですべての行をスキップするか、単にseekを記録しておいてください。

+0

私が間違っている場合は私を修正しますが、コマンドラインでファイル名を渡すと、<>でアクセスできなくなるか、stdinをリダイレクトする場合にのみファイル名が渡されますか? –

+0

あなたは正しいです。あなたのソリューションは完璧に動作しますが(エンコーディングは必要ありませんが、meh)、私の解決策はオートディーを通過しなければならないエラーチェックも自動的に実行されます。もう少しスケーラビリティがあります。何か他のものが既にARGVを詰まらせていたプロジェの途中に現れるかもしれないからです。 – Hugmeir

関連する問題