大数据量分析,perl 段错误

大数据量分析,perl 段错误

一个数据文件1亿多条,格式如下:
id          name             idnumber                         creatime                  
----------- ---------------- -------------------------------- --------------------------
          6 liping           210102771215212                         Sep  8 2004  9:17AM
         12 liu0001           310102810120774                         Sep  8 2004  9:45AM

功能: 找相同的idnumber 个数大于等于100 的行
OS:linux 2.6.17
内存:32G

刚开始,是把所有记录读入hash,计数,结果内存溢出!
然后,分步处理, 只要相同的到了100就打印出来,然后删hash值,结果是段错误,不知道为什么?

#!/usr/bin/perl -w

use strict;

my %sameId;
my $max='100';
while (<>)
{
#       print "__$_\n";

        if ( my ($uid,$name,$idnum) = $_ =~ /^[ \t]*(\d+)[ \t]*(\w+)[ \t]*(\w+)/ )
        {
#          print "$uid,$name,$idnum\n";

            $sameId{$idnum}++;
            if ($sameId{$idnum} == $max)
            {
                print "$idnum\n";
                delete $sameId{$idnum};
            }
        }
}
这段代码有问题吗? 请大牛们指点一下

也试着改系统的limit参数,将 stack改成unlimited,还是段错误

# ulimit -a
core file size        (blocks, -c) 16384
data seg size         (kbytes, -d) unlimited
file size             (blocks, -f) unlimited
max locked memory     (kbytes, -l) 32
max memory size       (kbytes, -m) unlimited
open files                    (-n) 1024
pipe size          (512 bytes, -p) 8
stack size            (kbytes, -s) 8192
cpu time             (seconds, -t) unlimited
max user processes            (-u) 278528
virtual memory        (kbytes, -v) unlimited
感觉是hash表太大了?
假如有1W条互不相同的记录的话,hash的键就有1W个了
具体怎么写,我还没想好,等待高人
没太看懂你的问题  你是想打印 100倍数的行吗?

$. 就是记录行号的特殊变量


QUOTE:
原帖由 damofeixue 于 2008-11-6 10:59 发表
这段代码有问题吗? 请大牛们指点一下

先用一个小点的数据文件测试一下。
数据量非常大的情况最好是分批处理,例如一次处理一百万条记录,将收集到的信息写入临时文件,释放内存,如此循环直到所有数据处理完,然后将所有临时文件中的结果汇总起来。当然,汇总临时文件时也可能需要分批。
建议lz用自然语言描述一下需求是什么。
我的理解是:找出文件中idnumber重复次数大于等于100的那个idnumber,是不是?
比如这是个登录日志,idnumber为用户id,那么就是找出登录次数大于等于100的用户了。

那么首先:
1. 等于100之后不能删hash的,否则>=200、>=300...的用户会被分别输出2次、3次、...
2. 如何解决?既然hash由于内存不足而不能使用,那么用磁盘怎么样?

把idnumber的一部分作为文件名,对idnumber进行归类,放到多个文件中。比如
210102771215212  中的 2101027712 部分作为文件名,
所有idnumber以2101027712开头的idnumber放到 2101027712.txt 中。
这样执行一便之后就会将原来的1亿条数据分割成许许多多的数字开头的文件,
而且各个文件之间数据不会重复(也就是说最终处理结果无需合并了)。
> 上面这个任务用 perl 一行就搞定了吧?

然后用bash写个循环,对这些txt文件依次做 sort -n | uniq -c
这样就可以统计出每个idnumber的出现次数。
因为上面已经分割过,每个文件最多10万条数据,32G内存处理应该不成问题

最后再查找出现次数>=100的,perl单行或者grep都行

最后别忘了把临时的.txt都删了就行了。

也用不着写perl程序了。


QUOTE:
原帖由 odacharlee 于 2008-11-6 13:06 发表
建议lz用自然语言描述一下需求是什么。
我的理解是:找出文件中idnumber重复次数大于等于100的那个idnumber,是不是?
比如这是个登录日志,idnumber为用户id,那么就是找出登录次数大于等于100的用户了。

...

很专业
可惜没有那么大的文件来测试一下,搞不懂哪里的问题。

不过,你不必要用 正则式 的, split 一下就可以。
首先感谢各位的关注~:)

最终我是将数据load data到数据库,用sql的临时数据表,分组排序搞定了

用磁盘空间做缓存,分批处理是通用的方法,也是比较有效的,就是太麻烦