zoukankan      html  css  js  c++  java
  • 10G数据不用框架快速去重

    试想一下,如果有10G数据,或者更多;怎么才能够快速地去重呢?你会说将数据导入到数据库(mysql等)进行去重,或者用java写个程序进行去重,或者用Hadoop进行处理。如果是大量的数据要写入数据库也不是一件容易的事情,首先你需要开发一个程序将数据写入数据库,然后再用数据库的select distinct或者group by进行去重。如果是一次性的工作,这种方式显得就比较笨拙了。那么有没有更好的办法呢?下面记录一下我是怎么从10G数据里面迅速去重的。这里采用shell脚本的方式进行处理。

    说明

    • 这10G数据分布在七八个文件中

    • 文件编码格式为gb2312

    • 数据格式:

    "ID","已采","已发","内容","PageUrl"
    "1","1","1","====================会员名:鬼脚七||||||||||||||||||会员等级:军长第5年|||姓名:张三 |||====================会员名:鬼脚七||||||||||||||||||会员等级:军长第5年|||姓名:张三 |||====================会员名:鬼脚七||||||||||||||||||会员等级:军长第5年|||姓名:张三 |||====================会员名:鬼脚七||||||||||||||||||会员等级:军长第5年|||姓名:张三 |||","http://www.xxx.com/"
    "1","1","1","====================会员名:鬼脚七||||||||||||||||||会员等级:军长第5年|||姓名:张三 |||====================会员名:鬼脚七||||||||||||||||||会员等级:军长第5年|||姓名:张三 |||====================会员名:鬼脚七||||||||||||||||||会员等级:军长第5年|||姓名:张三 |||====================会员名:鬼脚七||||||||||||||||||会员等级:军长第5年|||姓名:张三 |||","http://www.xxx.com/"
    "1","1","1","====================会员名:鬼脚七||||||||||||||||||会员等级:军长第5年|||姓名:张三 |||====================会员名:鬼脚七||||||||||||||||||会员等级:军长第5年|||姓名:张三 |||====================会员名:鬼脚七||||||||||||||||||会员等级:军长第5年|||姓名:张三 |||====================会员名:鬼脚七||||||||||||||||||会员等级:军长第5年|||姓名:张三 |||","http://www.xxx.com/"



    数据格式说明:

    • 上面是3行数据
    • 每行都是5个field
    • 每个field间用“,”隔开
    • 而需要的内容在第4个field(也就是内容这个field)
    • 内容field间会员用“ ==================== ”隔开
      要达到的效果:将会员信息提取出来并去重

    实现思路和测试

    1.由于文件编码是gb2312编码,所以第一步是将文件编码转成utf-8编码

    iconv -c -f gb2312 -t utf-8 test.txt > test2.txt

    这里我们用linux系统自带的iconv命令进行转换,-c的意思是将无法识别的字符直接忽略掉

    2、获取会员信息,由于是第4个field,因而我们只需要获取第四个field即可,这里采用awk命令获取

    awk 'BEGIN{ FS=",";}{ print $4 }' test2.txt > test_menber.txt

    awk指定分隔符的方法为FS=”,”,运行后的结果如下

    vi test_menber.txt
    "内容"
    "====================会员名:鬼脚七||||||||||||||||||会员等级:军长第5年|||姓名:张三 |||====================会员名:鬼脚七||||||||||||||||||会员等级:军长第5年|||姓名:张三 |||====================会员名:鬼脚七||||||||||||||||||会员等级:军长第5年|||姓名:张三 |||====================会员名:鬼脚七||||||||||||||||||会员等级:军长第5年|||姓名:张三 |||"
    "====================会员名:鬼脚七||||||||||||||||||会员等级:军长第5年|||姓名:张三 |||====================会员名:鬼脚七||||||||||||||||||会员等级:军长第5年|||姓名:张三 |||====================会员名:鬼脚七||||||||||||||||||会员等级:军长第5年|||姓名:张三 |||====================会员名:鬼脚七||||||||||||||||||会员等级:军长第5年|||姓名:张三 |||"
    "====================会员名:鬼脚七||||||||||||||||||会员等级:军长第5年|||姓名:张三 |||====================会员名:鬼脚七||||||||||||||||||会员等级:军长第5年|||姓名:张三 |||====================会员名:鬼脚七||||||||||||||||||会员等级:军长第5年|||姓名:张三 |||====================会员名:鬼脚七||||||||||||||||||会员等级:军长第5年|||姓名:张三 |||"

    这里已经获取到了会员的信息;但是一行有多个会员的信息,而个数又是不固定的。因此下面是想办法一行显示一个会员

    3、一行显示一个会员

    由于会员信息间通过“====================”分割,要实现一行显示一个会员只需要将“====================”替换成换行即可。

    sed -i "s/====================/
    /g" test_menber.txt

    查看test_menber.txt的内容

    vi test_menber.txt 
      1 "内容"
      2 "
      3 会员名:鬼脚七||||||||||||||||||会员等级:军长第5年|||姓名:张三 |||
      4 会员名:鬼脚七||||||||||||||||||会员等级:军长第5年|||姓名:张三 |||
      5 会员名:鬼脚七||||||||||||||||||会员等级:军长第5年|||姓名:张三 |||
      6 会员名:鬼脚七||||||||||||||||||会员等级:军长第5年|||姓名:张三 |||"
      7 "
      8 会员名:鬼脚七||||||||||||||||||会员等级:军长第5年|||姓名:张三 |||
      9 会员名:鬼脚七||||||||||||||||||会员等级:军长第5年|||姓名:张三 |||
         10 会员名:鬼脚七||||||||||||||||||会员等级:军长第5年|||姓名:张三 |||
         11 会员名:鬼脚七||||||||||||||||||会员等级:军长第5年|||姓名:张三 |||"
         12 "
         13 会员名:鬼脚七||||||||||||||||||会员等级:军长第5年|||姓名:张三 |||
         14 会员名:鬼脚七||||||||||||||||||会员等级:军长第5年|||姓名:张三 |||
         15 会员名:鬼脚七||||||||||||||||||会员等级:军长第5年|||姓名:张三 |||
         16 会员名:鬼脚七||||||||||||||||||会员等级:军长第5年|||姓名:张三 |||"
    



    4、替换掉其他字符“””、空行和“|||”

    #将“"”替换成空字符串
    sed -i "s/"//g" test_menber.txt
    #删除空行
    sed -i '/^$/d' test_menber.txt
    #将分隔符|||换成@
    sed -i "s/|||/@/g" test_menber.txt



    5、根据会员名去重

    sort -t $"@" -k 1,1 -su test_menber.txt >test_uniq.txt

    -t可以指定分隔符,-k指定排序的field, -su表示稳定排序并去重

    查看结果

    [root@bogon yichen]# more test_uniq.txt 
    会员名:鬼脚七@@@@@@会员等级:军长第5@姓名:张三 @
    内容

    思路和测试完成了,但是文件比较多,一个个文件去处理也比较麻烦。因而写个脚本去处理即可

    脚本批量处理

    1、转换文件编码

    [root@bogon yichen]# vi iconv_shell.sh 
    #!/bin/sh
    if [ "$#" != "2" ]; then
    echo "Usage: `basename $0` dir filter"
    exit
    fi
    echo $1
    for file in `find $1 -name "$2"`; do
    echo "$file"
    iconv -c -f gb2312 -t utf8 $file > ${file}_utf8

    调用./iconv_shell.sh 目录 文件通配符,例如:

    ./iconv_shell.sh ./ "*txt"

    此时生成的文件后缀为:.txt_utf8

    2、提取会员信息

    vi awk_filler.sh 
    #!/bin/sh
    if [ "$#" != "2" ]; then
    echo "Usage: `basename $0` dir filter"
    exit
    fi
    for file in `find $1 -name "$2"`; do
    echo "$file"
    awk 'BEGIN{ FS=",";}{ print $4 }' $file > ${file}_menber
    done

    调用

    ./awk_filler.sh ./ "*.txt_utf8"

    此时生成的文件后缀为:.txt_utf8 _menber

    3、替换“ ==================== ”、“””、“|||”和换行

    vi sed_shell.sh 
    #!/bin/sh
    if [ "$#" != "2" ]; then
    echo "Usage: `basename $0` dir filter"
    exit
    fi
    for file in `find $1 -name "$2"`; do
    echo "$file"
    sed -i "s/====================/
    /g; s/"//g; /^$/d; s/|||/@/g" $file
    done
    
    for file in `find $1 -name "$2"`; do
    echo "$file"
    sed -i "/^$/d" $file
    done
    

    sed支持多表达式:sed “表达式1;表达式2” filename,注意表达式之间用“;”号隔开。

    调用:

    sh ./sed_shell.sh ./ "*.txt_utf8_menber"

    替换后的文件后缀仍为txt_utf8_menber

    4、去重

    vi uniq_shell.sh 
    #!/bin/sh
    if [ "$#" != "2" ]; then
    echo "Usage: `basename $0` dir filter"
    exit
    fi
    for file in `find $1 -name "$2"`; do
    echo "$file"
    sort -t $"@" -k 1,1 -su ${file} >${file}_uniq
    done

    调用:

    sh ./uniq_shell.sh ./ "*.txt_utf8_menber"

    最后生成去重后的文件后缀为txt_utf8_menber_uniq

    其实也可以放在一个shell脚本里面完成,这里就不再阐述了。想想看10G的文件用几个简单的命令就完成了去重,可见linux的强大。所以说学几个简单的linux命令还是很有必要的,这样可以大大地降低你的工作量,提高工作的效率。

  • 相关阅读:
    一篇文章读懂JSON
    不该被忽视的CoreJava细节(四)
    Java面试题总结(二)
    Java面试题总结(一)
    不该被忽视的CoreJava细节(三)
    不该被忽视的CoreJava细节(一)
    逐步解读String类(一)
    JSP注释格式
    命令行启动mysql服务
    经典进程的同步问题之——生产者&&消费者
  • 原文地址:https://www.cnblogs.com/ainima/p/6331789.html
Copyright © 2011-2022 走看看