免费注册 查看新帖 |

Chinaunix

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

[文本处理] 请教大神:awk大文本分组统计性能问题 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2017-04-20 22:38 |只看该作者 |倒序浏览
代码非常简单,就是去掉第一列,然后统计后面其他出现的次数并打印至新文件。

文本大小10G左右,内存16G,这代码似乎在for的时候性能太低,IO根本利用不起来。

2G的文件几分钟就处理完了,但10G的文件好几个小时都没处理完,这是肿么回事?
本想不要for,在处理行时写入另外一个数组,打印就一次打印出来。
可是,内存不够啊?还有,该怎么写呢?

莫非,只能拆分文件了?
想着拆分文件会比较麻烦(分组统计后然后再合并,再分组统计……)

       awk '
            {
                $0=$2" "$3" "$4" "$5" "$6
                CNT[$0]++
            }
            END{
                for(K in CNT)
                    print K, CNT[K]
            }
        ' ${old_file} > ${new_file}

请多指点!

论坛徽章:
145
技术图书徽章
日期:2013-10-01 15:32:13戌狗
日期:2013-10-25 13:31:35金牛座
日期:2013-11-04 16:22:07子鼠
日期:2013-11-18 18:48:57白羊座
日期:2013-11-29 10:09:11狮子座
日期:2013-12-12 09:57:42白羊座
日期:2013-12-24 16:24:46辰龙
日期:2014-01-08 15:26:12技术图书徽章
日期:2014-01-17 13:24:40巳蛇
日期:2014-02-18 14:32:59未羊
日期:2014-02-20 14:12:13白羊座
日期:2014-02-26 12:06:59
2 [报告]
发表于 2017-04-21 12:01 |只看该作者
回复 1# Lovcplus

Key point: CNT[$0]++

$ awk -vBAR_DEBUG_TEN=1 -f bar.awk 500M.txt
Read 500M.txt ... (for lines only by wc utility)
    500M.txt has 18213494 lines
11:51:32 start, total items:18213494   
10.0% [======|.....................................................] 00:05
20.0% [============\...............................................] 00:10
30.0% [==================*.........................................] 00:15
40.0% [========================*...................................] 00:28  took more time
50.0% [==============================/.............................] 00:45
60.0% [====================================|.......................] 01:21
60.8% [====================================\.......................] 01:32^C




$ cat bar.awk
function bar_set(num, msg,  cmd, wid, len,dot){
  _bar_sec_sys = systime();
  printf("%s start, total items:%s   %s\n", strftime("%H:%M:%S"), num, msg);
  _bar_per_all = num;
  _bar_wid = 80;
  _bar_stp = int(num /20000)+1;
  cmd = "tput cols";
  cmd | getline wid;
  close(cmd);
  if(wid != 0) _bar_wid = wid;

  #123456789012345678901234567890123456789012345678901234567890
  #100.0% [====================] 01:00:00
  # (6)  7      (>20)          30  (8)  39   

  if(_bar_wid < 40){
    print "The screen columns is too small(" _bar_wid ")";
    print "Please change it and more than 39" ;
    exit(1);
  }
  
  _bar_dot_all = _bar_wid - 20;

  _alv[1] = "*";
  _alv[2] = "\\";
  _alv[3] = "|";
  _alv[0] = "/";
  bar_make(1);
}
function bar_make(num,    n, per, dot, all, per_str, alv_str, dot_str, sec){
  _bar_num = num;
  per_str = sprintf("%5.1f% ", num / _bar_per_all * 100);

  dot = int(per_str / 100 * _bar_dot_all)
  _bar_cnt = ++_bar_cnt % 4;
  alv_str = _alv[_bar_cnt];

  if(_bar_num == 1 || dot != _bar_dot){
    _bar_dot = dot;
    _bar_dot_s = "";
    _bar_dot_e = "";
    for(n=0;n<dot; ++n)
      _bar_dot_s = _bar_dot_s"=";
    for(n = dot+1; n <_bar_dot_all; ++n)
      _bar_dot_e = _bar_dot_e".";
  }
  if(+per_str == 100) alv_str="";
  dot_str = _bar_dot_s alv_str _bar_dot_e;

  sec = systime() - _bar_sec_sys;
  if(_bar_num ==1 || sec != _bar_sec){
    _bar_sec = sec
    if(sec < 3600){
      _bar_sec_str = sprintf("%02d:%02d", int(sec/60), sec%60);
    }else{
      _bar_sec_str = sprintf("%02d:%02d:%02d", int(sec/3600),
                         int( (sec%3600)/60), sec%60);
    }
  }
  printf("\r%s[%s] %s", per_str, dot_str, _bar_sec_str);

  if(BAR_DEBUG_TEN){
    if(_bar_per_str != "" && +per_str != 100)
      if(per_str%10==0 && _bar_per_str != per_str)
        print "";
  }
  _bar_per_str = per_str;

}
function bar(num){
  if(num - _bar_num < _bar_stp) return;
  bar_make(num);
}
FNR==1{
  print " Read " FILENAME " ... (for lines only by wc utility)"
  cmd="wc -l " FILENAME;
  cmd | getline line;
  print "    " FILENAME " has " (+line) " lines"
  close(cmd);
}
FNR == 1{
  bar_set(+line);
}
{
  bar(FNR)
  # do something by yourself
  #$0=$2" "$3" "$4" "$5" "$6
  CNT[$0]++

}
END{
  print""
}

论坛徽章:
2
射手座
日期:2014-10-10 15:59:4715-16赛季CBA联赛之上海
日期:2016-03-03 10:27:14
3 [报告]
发表于 2017-04-21 13:10 |只看该作者
回复 1# Lovcplus

END{
                for(K in CNT)
                    print K, CNT[K];                    delete CNT[k];
            }

论坛徽章:
0
4 [报告]
发表于 2017-05-04 11:39 |只看该作者
非常抱歉,太多事耽搁,回复晚了!

非常感谢@jason680的耐心。

目前原因可能找到,应该是文本中唯一的记录确实太多了。。。

文本是通过多个awk同时写入得来,可能导致行错乱。

目前还没有很好的解决方案,择日再向您请教。

同时感谢@yinyuemi的回复,在awk处理完成后内存应该就会自动释放。

论坛徽章:
0
5 [报告]
发表于 2017-05-04 11:43 |只看该作者
10375.6613MB        48073
9360.6590MB        4870
3604.7540MB        158
3137.8229MB        150
5010.9667MB        133
1819.4434MB        91
1979.1187MB        91
1547.2400MB        83
1856.4467MB        77
1436.9940MB        70
1375.0859MB        55
657.5222MB        31
623.7116MB        28
651.5420MB        28
660.8960MB        26
579.2533MB        26
528.4417MB        25
457.6146MB        23
418.9754MB        22
312.2737MB        18

以上是文件大小及耗时(秒)记录,明显不正常。

论坛徽章:
145
技术图书徽章
日期:2013-10-01 15:32:13戌狗
日期:2013-10-25 13:31:35金牛座
日期:2013-11-04 16:22:07子鼠
日期:2013-11-18 18:48:57白羊座
日期:2013-11-29 10:09:11狮子座
日期:2013-12-12 09:57:42白羊座
日期:2013-12-24 16:24:46辰龙
日期:2014-01-08 15:26:12技术图书徽章
日期:2014-01-17 13:24:40巳蛇
日期:2014-02-18 14:32:59未羊
日期:2014-02-20 14:12:13白羊座
日期:2014-02-26 12:06:59
6 [报告]
发表于 2017-05-04 15:56 |只看该作者
本帖最后由 jason680 于 2017-05-04 22:43 编辑

回复 5# Lovcplus

>> ...以上是文件大小及耗时(秒)记录,明显不正常。

不正常!!??

举个例子,你想一下,你有个仓库,
放100件物品,没有走道空间
放80件物品(以下),有走道空间

放80件以上到100件物品,走道空间不足
走道空间不足取物会困难,
你要取出在内部,你先要搬移一些物品...
才能取得你要的物品....多花时间

放80件物品以下,走道空间充足
要取物,可以直接取,不须搬来搬去......

-----------------------------------
something wrong ?

3604.7540MB        158
3137.8229MB        150
5010.9667MB        133
1819.4434MB        91
1979.1187MB        91

论坛徽章:
6
数据库技术版块每日发帖之星
日期:2015-11-27 06:20:00程序设计版块每日发帖之星
日期:2015-12-01 06:20:00每日论坛发贴之星
日期:2015-12-01 06:20:0015-16赛季CBA联赛之佛山
日期:2017-03-26 23:38:0315-16赛季CBA联赛之江苏
日期:2017-07-17 10:08:4415-16赛季CBA联赛之北京
日期:2018-03-04 17:01:50
7 [报告]
发表于 2017-05-04 17:31 |只看该作者
拆分文件会比较麻烦

论坛徽章:
0
8 [报告]
发表于 2017-05-05 11:38 |只看该作者
回复 6# jason680

您说得有道理。
我说不正常比如说这两个文件的去重:

10375.6613MB        48073
9360.6590MB        4870


10G文件的去重花费的时间是9G的文件的10倍。


您的意思还是因为内存(16G)不够?
10G文件去重时我观察内存消耗14G,cache竟然达到30G+。
可能是我需要修改解决方案了。


这里还是把问题描述一下吧,如果您有更好的解决方案,还请指点。


5W个左右客户端每天会提交100W个左右的gz文件(总数据行在50亿左右)上来,字段如下:
clientid typeid code name msg


typeid 约5K个。

需求:服务端需要进行分组统计,如提交此typeid,code的clientid的个数。

解决方案如下:

1.解压 :
  用c实现。一次性解压到对应文本(也就是最终会生成100W个文本,每个文本约300K)。
  用zcat | awk 效率太低。

2.追加写
  开启50个awk遍历这些文件,并追加写入typeid.txt中,如0001.txt...5000.txt
  这样会有问题,awk的并发可能导致文本行错乱。
  不过这种错乱暂时可以忽略,经过多次测试,在文本行足够短小的情况下,错乱的情况比较小。

3.去重
  awk单个处理每个文件
  忽略错乱的行,比如根据列字符的长度,数值等判断。
  然后!a[$0]++

4.统计
  awk单个处理去重后的文件
  然后分组统计,也就是帖子最开始的算法。


不知您是否有更好的解决方案。
目前处理时间是40+小时,期待在24小时内处理完成。
(目前看来主要是某几个typeid的文件在去重和统计时耗时太多,比如上面提及的48073,一个文件的去重需要13小时之多)

再次对您的关注表示非常感谢。

论坛徽章:
0
9 [报告]
发表于 2017-05-05 16:05 |只看该作者
提示: 作者被禁止或删除 内容自动屏蔽

论坛徽章:
0
10 [报告]
发表于 2017-05-05 18:37 |只看该作者
回复 9# 本友会机友会摄友会

事实上就是用mysql完成最后的分组统计的(还有更细业务需求的分组统计,如某列的百分比)。在去重并初步分组后再合并最后文本在10G左右,mysql单表无索引在4小时内处理完成。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP