Bash:uniq计数大数据集

标签 bash uniq

我有一组超过 70GB 的 CVS 文件,其中 35GB 是我感兴趣的字段(每行大约有 100 个字节)

数据高度重复(采样显示前 1000 条覆盖了 50% 以上的行),我有兴趣获取总 uniq 计数

对于不太大的数据集,我会这样做

cat my.csv | cut -f 5 | sort | uniq -c | sort --numeric而且效果很好

但是我遇到的问题是(据我了解)由于中间 sort ,此命令需要将整个数据集保存在 RAM 中(然后保存在磁盘上,因为它不适合我的 16Go RAM),然后将其流式传输到 uniq -c

我想知道是否有命令/script awk/python 来执行 sort | uniq -c一步到位,RAM 消耗就会低得多?

最佳答案

你可以试试这个:

perl -F, -MDigest::MD5=md5 -lanE 'say unless $seen{ md5($F[4]) }++' < file.csv >unique_field5.txt

它将在内存中保存每个唯一 field-5 的 16 字节长的 md5-digest(例如 $F[4])。或者你可以使用

cut -d, -f5 csv | perl -MDigest::MD5=md5 -lnE 'say unless $seen{md5($_)}++'

相同的结果。

当然,现在 md5 在加密上并不安全,但可能足以进行排序...当然,可以使用 sha1sha256,只需使用-MDigest::SHA=sha255。当然,sha-digests 更长 - 例如需要更多内存。

与注释中链接的awk类似,不同之处在于,这里用作散列键的不是整个输入行,而是仅16byte长MD5摘要。

编辑

因为我想知道性能,所以创建了这个测试用例:

# this perl create 400,000,000 records
# each 100 bytes + attached random number,
# total size of data 40GB.
# each invocation generates same data (srand(1))
# because the random number is between 0 - 50_000_000
#    here is approx. 25% unique records.
gendata() {
perl -E '
    BEGIN{ srand(1) }
    say "x"x100, int(rand()*50_000_000) for 1..400_000_000
'
}

# the unique sorting - by digest
# also using Devel::Size perl module to get the final size of the data hold in the memory

# using md5
domd5() {
    perl -MDigest::MD5=md5 -MDevel::Size=total_size -lnE '
        say unless $seen{md5($_)}++;
        END {
            warn"total: " . total_size(\%seen);
        }'
}
#using sha256
dosha256() {
    perl -MDigest::SHA=sha256 -MDevel::Size=total_size -lnE '
        say unless $seen{sha256($_)}++;
        END {
            warn"total: " . total_size(\%seen);
        }'
}

#MAIN
time gendata | domd5    | wc -l 
time gendata | dosha256 | wc -l 

结果:

total: 5435239618 at -e line 4, <> line 400000000.
 49983353

real    10m12,689s
user    12m43,714s
sys 0m29,069s
total: 6234973266 at -e line 4, <> line 400000000.
 49983353

real    15m51,884s
user    18m23,900s
sys 0m29,485s

例如:

md5

  • 内存使用量:5,435,239,618 字节 - 例如约 5.4 GB
  • 唯一记录:49,983,353
  • 运行时间:10 分钟

对于 sha256

  • 内存使用量:6,234,973,266 字节 - 例如约 6.2 GB
  • 唯一记录:49,983,353
  • 运行时间:16 分钟

相比之下,使用“通常”方法进行纯文本唯一搜索:

doplain() {
        perl -MDevel::Size=total_size -lnE '
                say unless $seen{$_}++;
                END {
                        warn"total: " . total_size(\%seen);
                }'
}

例如运行:

time gendata | doplain | wc -l

结果:

  • 内存使用量要大得多:10,022,600,682 - 我的 16GB RAM 笔记本开始大量交换(因为有 SSD,所以没什么大不了的 - 但仍然..)
  • 唯一记录:49,983,353
  • 运行时间:8:30 分钟

结果?

只需使用

cut -d, -f5 csv | perl -MDigest::MD5=md5 -lnE 'say unless $seen{md5($_)}++'

你应该足够快地获得独特的线条。

关于Bash:uniq计数大数据集,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43425227/

相关文章:

linux - 堆叠多个 libnotify 弹出窗口

linux - Postfix 后队列内容过滤器不起作用

linux - 使用列条件在 uniq 之后打印行

linux - 如何在 bash 中解决这个安全难题?

linux - 将两个或多个 STDOUT 重定向到单个 STDIN

linux - 尝试在bash中使用变量将stderr重定向到/dev/null

linux - 为什么我需要对 uniq 进行排序以删除重复行?

linux - 在 bash 中计算文件中的单词出现次数

ruby - 解释 Ruby Array uniq 方法的一个表达式

linux - 带有重定向的 linux uniq 命令出错