【问题标题】:sort and sum for large data files大数据文件的排序和求和
【发布时间】:2013-11-07 09:47:13
【问题描述】:

我必须处理sort 似乎无法处理的文件。 这些文件是 apprx。每个 3 GB。

输入如下:

last-j  nmod+j+n    year-n 9492
last-j  nmod+j+n    night-n 8075
first-j nmod+j+n-the    time-n 7749
same-j  nmod+j+n-the    time-n 7530
other-j nmod+j+n-the    hand-n 5319
ast-j   nmod+j+n   year-n 1000
last-j   nmod+j+n   night-n 5000
first-j   nmod+j+n-the   time-n 1000
same-j   nmod+j+n-the   time-n 3000
other-j   nmod+j+n-the   hand-n 200

我需要将相应重复的数量相加。

所以想要的输出如下:

   last-j   nmod+j+n    year-n 10492
    last-j  nmod+j+n    night-n 13075
    first-j nmod+j+n-the    time-n 8749
    same-j  nmod+j+n-the    time-n 10530
    other-j nmod+j+n-the    hand-n 5519

我一直在尝试这个排序命令,应该可以解决问题

sort input | uniq -c | awk '{print $2 "\t" $3 "\t" $1*$4}' 

它的内存不足。关于可能更优化以处理更大数据文件的任何建议?谢谢

【问题讨论】:

  • 如何定义重复项?相同的三列?添加预期输出,使其更清晰。
  • 查看更新的问题 -- 我包含了想要的结果。
  • 目前还不清楚你想要什么。为什么输出包含两行other-j nmod+j+n-the hand-n
  • 对不起!更新了所需的结果 - 它们现在是准确的,我在编写时出错了。它只是将 Cols 1-3 中的重复项相加并添加频率。在 Col4

标签: sorting awk uniq


【解决方案1】:

awk 中使用数组可以一起完成,无需sortuniq

$ awk '{a[$1,$2,$3]+=$4} END{for (i in a) print i, a[i]}' file
first-jnmod+j+n-thetime-n 8749
ast-jnmod+j+nyear-n 1000
same-jnmod+j+n-thetime-n 10530
last-jnmod+j+nnight-n 13075
last-jnmod+j+nyear-n 9492
other-jnmod+j+n-thehand-n 5519

因为这是使用 col 1, 2, 3 作为索引,所以它们被写在一起。将它们放在另一个数组中可以解决这个问题:

$ awk '{a[$1,$2,$3]+=$4; b[$1,$2,$3]=$1" "$2" "$3} END{for (i in a) print b[i], a[i]}' a
first-j nmod+j+n-the time-n 8749
ast-j nmod+j+n year-n 1000
same-j nmod+j+n-the time-n 10530
last-j nmod+j+n night-n 13075
last-j nmod+j+n year-n 9492
other-j nmod+j+n-the hand-n 5519

【讨论】:

  • 谢谢,在一个示例文件上,它似乎工作得很好,尽管我对我的确切输入 $ awk '{a[$1,$2,$3]+=$4; b[$1,$2,$3]=$1"\t"$2"\t"$3} END{for (i in a) print b[i], a[i]}' 做了一些小改动。您认为这可以处理最大 10GB 的文件吗?还是更好地继续分段工作并连接?
  • 数组会变得很大,但应该可以工作,@owwoow14。请注意,像您所做的那样在三个块中进行管道可能会使其变慢。可以在命令前用time查看一下,然后告诉我吗?
  • 更新:尝试 7.6 GB 的文件,该过程正在进行 80 分钟。 -- 仍然没有打印到输出 // 在服务器中使用 8G 的 vm。交叉手指,它将输出......
  • 抱歉,在 +13 小时后将服务器吸干了所有值得的东西 (+16g) - 不得不杀死它。系统管理员对我不太满意。
  • 用真实数据很难说,但也许你可以测试一下:用我的脚本获取 1 GB 的文件并检查 1) 需要多长时间。 2) 对文件进行排序,然后使用不将所有值存储在数组中的 awk 版本。取决于哪个更快,然后继续。奇怪的是花了这么多:(
【解决方案2】:

sort 和其他纯粹的神奇 UNIX 工具已尽可能优化——可能——可以。如果您正在对文件中的条目进行计数,并且它们的唯一出现次数不适合内存,则将它们加载到内存中并不是一个好的解决方案——否则这是最快的方法。

除此之外,对文件进行排序——O(n log n)——,然后计算条目——O(n)——当然是最好的解决方案——除非你保留一个k-size的条目映射在内存中,并在尝试将k + 1 键添加到映射时继续将数据从内存交换到磁盘。考虑到这一点,您的解决方案(带有sort + uniq + awk 的单行)只需轻轻一点。

尝试在外部sort 文件,使用sort 的魔法能力这样做;之后,计数最多需要在内存中保存一个条目——这几乎可以解决您的问题。最后的双线可能是这样的:

sort -T <directory_for_temp_files> <input> > <output>
awk '{
    if (cur == "$1 $3") { freq += $4; }
    else { printf "%s %d\n", cur, freq; cur = "$1 $3"; freq = $4; }
}' < <output> > <final_output>

【讨论】:

    【解决方案3】:

    如果这是内存不足,那是因为sort 因为uniqawk 只消耗恒定数量的内存。您可以使用 GNU 并行运行多种排序,例如来自手册:

    cat bigfile | parallel --pipe --files sort | parallel -Xj1 sort -m {} ';' rm {} >bigfile.sort
    

    这里的大文件被分成大约 1MB 的块,每个块以 '\n'(这是 --recend 的默认值)。每个块都传递给排序 sort 的输出保存到文件中。这些文件通过 到在它之前的文件上运行 sort -m 的第二个并行 删除文件。输出保存到 bigfile.sort。

    文件排序后,您可以通过您使用的uniq/awk 管道进行流式传输,例如:

    cat bigfile.sort | uniq -c | awk '{print $2 "\t" $3 "\t" $1*$4}'
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-05-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-07-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多