哈希效率与大量数据

时间:2013-07-12 20:16:23

标签: perl

我有这样的数据:

1 10
1 30
1 40
1 10
2 20
2 20
2 30
3 50
3 10
3 10
3 10
4 20
4 10

如果第一列的值匹配,我想将所有值加起来,结果就是这样,

1 90
2 70
3 80
4 30

我的代码在这里,

while (<DATA>) 
{
my ($a, $b) = split;
$hash{$a}  += $b;
}

foreach $a (sort keys %hash) 
{
$b = $hash{$a};
print OUT "$a $b\n";
}

它适用于样本数据(大约100MB),但处理我的真实数据(大约100G)似乎需要很长时间。有没有办法优化我的代码?

提前感谢任何建议!

3 个答案:

答案 0 :(得分:3)

正如其他人所说,你最可能的瓶颈不是哈希或Perl,而是磁盘访问。

将文件拆分为更小的块。 (如果可以的话,使用标准的Unix utils。)

将它们存储在SEPARATE IO源上(理想情况下,不同的控制器上的不同磁盘,最好是在不同的PC上)。

  • 如果你只有几个键(例如每个键大于100-1000行),只需单独运行块,然后将它们全部连接成100x小文件,并整理一个文件。

  • 否则,使用数据库同步处理以存储总和。

答案 1 :(得分:2)

哈希非常有效率。它们可能是解决您问题的最佳方案。但是,根据您的数据,可能会有例外情况:

  • 如果所有键都是(或多或少)连续范围内的整数,那么您可以使用数组,这比散列更有效:

    while (<DATA>) {
      my ($k, $v) = split;
      $array[$k] += $v;
    }
    
    for my $i (grep defined $array[$_], 0 .. $#array) {
      print "$i $array[$i]\n";
    }
    
  • 如果密钥已经排序,我们不需要任何中间数据结构。只需将总和累加到标量中。当密钥更改时,输出最后一个密钥的总和。

  • 如果您有多个文件,则可以并行应用每个文件的算法并合并结果。这使您的代码以对数时间而不是线性时间运行(也称为大赢)。要么将大文件拆分成较小的块,我们会使用seektell对文件进行分区。处理器越繁忙,文件汇总的速度就越快。 有一点需要注意:很可能I / O是你的瓶颈。如果必须定期执行此任务,则使用SSD(而不是HDD)可能会显着提高性能。

答案 2 :(得分:1)

如果您的数据看起来像是向我们展示的,那么您似乎按键排序,因此根本不需要哈希。

perl -anE'if($k!=$F[0]){say"$k $s"if$.>1;$k=$F[$s=0]}$s+=$F[1]}{say"$k $s"'

会做到这一点。我怀疑它会很慢。