免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
123下一页
最近访问板块 发新帖
查看: 10886 | 回复: 28
打印 上一主题 下一主题

Perl实现80GB的文件5亿条记录与2K条记录的列表进行匹配,运行的速度很慢,求大虾指点 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2011-05-09 15:36 |只看该作者 |倒序浏览
本帖最后由 zhanminga 于 2011-05-11 22:50 编辑

问题:80GB的文件5亿条记录与2000条记录的列表进行匹配,运行的速度很慢,求大虾指点
问题进展:20110506 貌似跑完20W用时39分钟。
               20110509 一小时跑完100W数据。
               20110510 22点 的 137分钟跑完87GB的数据,结果数据大小11.58GB(逻辑无问题)。
               期待能并行或者其他的方法能进一步将时间缩短(在逻辑无问题的情况下)
-------------------------------------------------------------------------------------------------
环境: perl v5.8.2 + AIX          文件服务器上配置为 lcpu=8 mem=15360MB
文件wap_source (此文件大小为82GB,记录数为5亿条)内容如:
"8613488877513","NokiaE71","20110301235000","20110301235000","http://dh.uc.cn/?id=51394"
"8615116906023","MOT-A3000_CMCC/1.0 Release/09.09.2008 Profile/MIDP","20110301234959","20110301235000","http://3g.sina.com.cn/iask/ring/list.php?p=0&serial=436493081.365&vt=1&wm=4007&q=%E7%AD%89%E4%BD%A0%E7%88%B1%E6%88%91&p=dsymp3&w=dsymp31"

需进行匹配的文件vgop_wap_list(此文件记录数为2000条)内容如:
570,wap.baidu.com,ssid=0
120,mc60.z.qq.com,mc
580,dh.uc.cn,uc_common_param
580,dh.uc.cn
570,3g.sina.com.cn,iask
650,3g.sina.com.cn

匹配的最终结果内容如:
13488877513,20110301,580
15116906023,20110301,650
15116906023,20110301,570

#####################################################
代码判断:
中间判断为wap_source文件的网址及二级栏目与 文件列表vgop_wap_list中的网址及二级栏目进行匹配,
判断为:
1: wap_source中只有网址,那么直接跟vgop_wap_list中的网址进行匹配
2: wap_source中有网址并且有二级栏目,那么分2种情况与列表vgop_wap_list进行匹配
     a) 两者的网址匹配成功并且二级栏目也匹配成功则print
        b)wap_source中的网址与列表vgop_wap_list网址匹配成功(前提:列表中只有网址项,无二级栏目), 则print

#逗号分割
my @wap_r = split(/,/);
#对逗号分割后的最后一个元素,进行二次分割
#如有的url为http://3g.qq.com/news/?id=htpp:// 这类的数据进行,而且可以去掉前面的htpp:// 只取其网址及随后的二级栏目
my @my_url_d = split(/^http:\/\//,$wap_r[4]);
#对取出来的网址及二级栏目进行分割,并在下面可进行比较
my @url = split(/\//,$my_url_d[1]);

#####################################################
代码逻辑符合需要, 另外vgop_wap_list文件中的有一些大家提到的
许多形如“240,wap.baoruan.com,/download/datalist/list/class/signtoplist/" 这样的数据
这类数据我会在之后进行丢弃处理,先不予考虑,随后会把新的列表文件传上来

解说一下:
87GB的A文件分为5个接口而来(5个文件),所以考虑是否直接用5个接口文件来进行。另:是否能考虑并行 或多线程等方式
(每个接口的文件为10分钟下载一次,一个接口一天有6*24个文件,最后按接口合并为一个总的文件)
#####################################################

另附代码如下:
iamlimeng 的程序 (20110510晚22点修改的代码为
跑完整个87GB的单个文件 大概需要137分钟跑完,(感谢iamlimeng 抽出宝贵的时间)
20110510晚22点修改的代码为)(代码测试通过)
用现有的vgop_wap_list列表文件,处理87GB的文件,处理完得结果文件为11.58GB 跟预估的11GB左右差不多,
耗时:8251 wallclock secs (7335.76 usr + 179.76 sys = 7515.52 CPU)
  1. #!/usr/bin/perl

  2. use strict;
  3. my %list;
  4. open(IN,"vgop_wap_list")||die("wap list file not find!");
  5. while (<IN>) {
  6.         chomp;
  7.          my @temp = split /,/;
  8.          if ($#temp == 2) { push(@{$list{2}{$temp[1]}{$temp[2]}},$temp[0]); }
  9.          elsif ($#temp == 1) { push(@{$list{1}{$temp[1]}},$temp[0]); }

  10. }
  11. close IN;

  12. open(FH,">result.txt");
  13. open(FILEIN,"wap_source")||die("wap data file not find!");
  14. while (<FILEIN>) {
  15.         if (/(.*?),(.*?),(.*?),(.*?),(.*)/) {
  16.                  my @my_url_d = split(/http:\/\//,$5);
  17.                  my @url = split(/\//,$my_url_d[1]);
  18.                  my $tel_no = substr($1,-12,11);
  19.                  my $start_time = substr($3,1,8);
  20.                  if ($#url > 0 && $list{2}{$url[0]}{$url[1]}) {
  21.                           print FH "$tel_no,$start_time,$_\n" foreach (@{$list{2}{$url[0]}{$url[1]}});
  22.                  }
  23.                  if ($list{1}{$url[0]}) {
  24.                          print FH "$tel_no,$start_time,$_\n" foreach (@{$list{1}{$url[0]}});
  25.                  }
  26.         }
  27. }
  28. close FILEIN;
  29. close FH;
复制代码
修改前)(代码测试通过)
  1. #! perl
  2. #-----------------------------------
  3. # zhanming 20110506
  4. #-----------------------------------
  5. open(FILEIN,"wap_source")||die("wap data file not find!");       

  6. while (<FILEIN>) {
  7.         chomp;
  8.         s/"//g;
  9.         @wap_r = split(/,/);
  10. #        print "一级分割".$#wap_r.",";
  11.         if ($#wap_r eq 4) {
  12.                 @my_url_d = split(/^http:\/\//,$wap_r[4]);
  13. #二级分割
  14.                 @url = split(/\//,$my_url_d[1]);
  15.                 $tel_no = substr($wap_r[0],-11,11);
  16.                 $start_time = substr($wap_r[2],0,8);

  17. #
  18.                 open(FILEIN_LIST,"vgop_wap_list")||die("wap list file not find!");
  19.                 while (<FILEIN_LIST>) {
  20.                 chomp;
  21.                 @wap_list = split(/,/);       
  22.                 if ($#url gt 0){
  23. #列表进行比对                               
  24.                         if ($#wap_list eq 2 ){
  25.                                 if (($wap_list[1] eq $url[0]) && ($wap_list[2] eq $url[1]) ) {
  26.                                                 print $tel_no.",".$start_time.",".$wap_list[0]."\n";
  27.                                 }
  28.                         }else{
  29.                                 if ($wap_list[1] eq $url[0]) {
  30.                                         print $tel_no.",".$start_time.",".$wap_list[0]."\n";
  31.                                 }
  32.                         }
  33. #               
  34.                 }else{       
  35.                         if ($#wap_list eq 1 ){
  36.                                 if ($wap_list[1] eq $url[0]) {
  37.                                         print $tel_no.",".$start_time.",".$wap_list[0]."\n";
  38.                                 }
  39.                         }
  40.                 }
  41.                 }
  42.                 close FILEIN_LIST;
  43. #
  44.         }
  45. }
  46. close FILEIN;
复制代码
感谢iamlimeng 的帮助!
20110509修改后,但是速度还是很慢,一个小时跑完100W记录的匹配   为:
  1. #!/usr/bin/perl

  2. use strict;
  3. use warnings;

  4. open(IN,"vgop_wap_list")||die("wap list file not find!");
  5. my @vgop_wap_list = <IN>;
  6. close IN;
  7. chomp @vgop_wap_list;
  8. my %vgop;
  9. foreach (@vgop_wap_list) {
  10.          @{$vgop{$_}} = split /,/;
  11. }

  12. open(FILEIN,"wap_source_100w")||die("wap data file not find!");
  13. while (<FILEIN>) {
  14.         if (/.*?,.*?,.*?,.*?,.*/) {
  15.                  chomp;
  16.                  s/"//g;
  17.                  my @wap_r = split(/,/);
  18.                  my @my_url_d = split(/^http:\/\//,$wap_r[4]);
  19.                  my @url = split(/\//,$my_url_d[1]);
  20.                  my $tel_no = substr($wap_r[0],-11,11);
  21.                  my $start_time = substr($wap_r[2],0,8);
  22.                  foreach (@vgop_wap_list) {
  23.                           if ($#url gt 0){
  24.                                    if ($#{$vgop{$_}} eq 2) {
  25.                                             if (${$vgop{$_}}[1] eq $url[0] && ${$vgop{$_}}[2] eq $url[1]){
  26.                                                    print $tel_no.",".$start_time.",".${$vgop{$_}}[0]."\n";
  27.                                          }
  28.                                    }
  29.                                    else {
  30.                                             if (${$vgop{$_}}[1] eq $url[0]) {
  31.                                                    print $tel_no.",".$start_time.",".${$vgop{$_}}[0]."\n";
  32.                                             }
  33.                                     }
  34.                           }
  35.                            else {
  36.                                    if ($#{$vgop{$_}} eq 1 && ${$vgop{$_}}[1] eq $url[0]){
  37.                                           print $tel_no.",".$start_time.",".${$vgop{$_}}[0]."\n";
  38.                                    }
  39.                            }
  40.                  }
  41.         }
  42. }
  43. close FILEIN;
复制代码

vgop_wap_list.rar

10.29 KB, 下载次数: 66

wap_source_1w.rar

402.39 KB, 下载次数: 60

论坛徽章:
0
2 [报告]
发表于 2011-05-09 16:19 |只看该作者
至少你应该将vgop_wap_list一次性读入内存,然后在内存中进行对比,这样20,21,22,23行可以少运算5亿次。

其他的没认真看。

论坛徽章:
0
3 [报告]
发表于 2011-05-09 16:30 |只看该作者
嗯  我试试 一次性读入

论坛徽章:
0
4 [报告]
发表于 2011-05-09 17:05 |只看该作者
  1. #!/usr/bin/perl

  2. use strict;
  3. use warnings;

  4. open(IN,"vgop_wap_list.txt")||die("wap list file not find!");
  5. my @vgop_wap_list = <IN>;
  6. close IN;
  7. chomp @vgop_wap_list;
  8. my %vgop;
  9. foreach (@vgop_wap_list) {
  10.          @{$vgop{$_}} = split /,/;
  11. }

  12. open(FILEIN,"wap_source.txt")||die("wap data file not find!");
  13. while (<FILEIN>) {
  14.         if (/.*?,.*?,.*?,.*?,.*/) {
  15.                  chomp;
  16.                  s/"//g;
  17.                  my @wap_r = split(/,/);
  18.                  my @my_url_d = split(/^http:\/\//,$wap_r[4]);
  19.                  my @url = split(/\//,$my_url_d[1]);
  20.                  my $tel_no = substr($wap_r[0],-11,11);
  21.                  my $start_time = substr($wap_r[2],0,8);
  22.                  foreach (@vgop_wap_list) {
  23.                           if ($#url gt 0){
  24.                                    if ($#{$vgop{$_}} eq 2) {
  25.                                             if (${$vgop{$_}}[1] eq $url[0] && ${$vgop{$_}}[2] eq $url[1]){
  26.                                                    print $tel_no.",".$start_time.",".${$vgop{$_}}[0]."\n";
  27.                                          }
  28.                                    }
  29.                                    else {
  30.                                             if (${$vgop{$_}}[1] eq $url[0]) {
  31.                                                    print $tel_no.",".$start_time.",".${$vgop{$_}}[0]."\n";
  32.                                             }
  33.                                     }
  34.                           }
  35.                            else {
  36.                                    if ($#{$vgop{$_}} eq 1 && ${$vgop{$_}}[1] eq $url[0]){
  37.                                           print $tel_no.",".$start_time.",".${$vgop{$_}}[0]."\n";
  38.                                    }
  39.                            }
  40.                  }
  41.         }
  42. }
  43. close FILEIN;
复制代码
小改了一下,应该能快一些。

另外,下面这几行,感觉也有点问题,但我不知道具体你要做什么,所以不好改:
my @wap_r = split(/,/);
my @my_url_d = split(/^http:\/\//,$wap_r[4]);
my @url = split(/\//,$my_url_d[1]);

论坛徽章:
0
5 [报告]
发表于 2011-05-09 17:07 |只看该作者
那几个if,应该也需要改,感觉很啰嗦!

论坛徽章:
0
6 [报告]
发表于 2011-05-10 13:03 |只看该作者
谢谢iamlimeng 的支持,但是速度这块还是存在很大的问题,一个小时跑完100W记录的匹配,

论坛徽章:
0
7 [报告]
发表于 2011-05-10 13:11 |只看该作者
#逗号分割
my @wap_r = split(/,/);
#对逗号分割后的最后一个元素,进行二次分割
#如有的url为http://3g.qq.com/news/?id=htpp:// 这类的数据进行,而且可以去掉前面的htpp:// 只取其网址及随后的二级栏目
my @my_url_d = split(/^http:\/\//,$wap_r[4]);
#对取出来的网址及二级栏目进行分割,并在下面可进行比较
my @url = split(/\//,$my_url_d[1]);

论坛徽章:
0
8 [报告]
发表于 2011-05-10 13:28 |只看该作者
不如给点数据,给告知判断逻辑,光说空的没用。

论坛徽章:
0
9 [报告]
发表于 2011-05-10 13:38 |只看该作者
回复 8# iamlimeng


    如何给  有联系方式吗

论坛徽章:
0
10 [报告]
发表于 2011-05-10 13:47 |只看该作者
中间判断为wap_source文件的网址及二级栏目与 文件列表vgop_wap_list中的网址及二级栏目进行匹配,
判断为:
1: wap_source中只有网址,那么直接跟vgop_wap_list中的网址进行匹配
2: wap_source中有网址并且有二级栏目,那么分2种情况与列表vgop_wap_list进行匹配
     a) 两者的网址匹配成功并且二级栏目也匹配成功则print
        b)wap_source中的网址与列表vgop_wap_list网址匹配成功(前提:列表中只有网址项,无二级栏目), 则print
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP