在大型文件上运行并行 awk 命令,无需额外的文件空间

在大型文件上运行并行 awk 命令,无需额外的文件空间

我正在尝试处理一个相当大的制表符分隔文件(约 30GB)。我可以运行 awk 来重新排列列,但它只使用我的 8 核机器的一个核心。我怎样才能使用所有核心?(并大大减少我的处理时间)而不物理地分割文件并占用更多磁盘空间?

cut -f3,4,5,6 original.tsv | awk 'BEGIN { FS="\t" }; { print $2"\t"$1"\t"$3"\t"$4 }' > abridged.tsv

我想做这样的事情,但又不想占用更多的磁盘空间:

split -l 50000 original.tsv sp
for i in $(dir sp*); do ./process_file.sh $i & done;

其中 process_file.sh 本质上就是上面的 cut/awk 语句。

再次强调,这里的关键问题是在不使用另外 30GB 的情况下完成此过程!有什么建议吗?

答案1

由于您使用“split”按行数分隔文件,然后分别处理它们并输出到不同的文件(我猜),您可以执行几个“awk”命令,每个命令仅根据行号处理文件的一部分:

$ cut -f3,4,5,6 original.tsv | awk 'BEGIN { FS="\t" }; (NR < 50000){ print $2"\t"$1"\t"$3"\t"$4 }' > abridged01.tsv
$ cut -f3,4,5,6 original.tsv | awk 'BEGIN { FS="\t" }; ((NR >= 50000) && (NR < 100000)){ print $2"\t"$1"\t"$3"\t"$4 }' > abridged02.tsv
$ cut -f3,4,5,6 original.tsv | awk 'BEGIN { FS="\t" }; ((NR >= 100000) && (NR < 150000)){ print $2"\t"$1"\t"$3"\t"$4 }' > abridged03.tsv

NR 是“awk”的内部变量,包含当前行号。每个命令只会处理其范围内的行。,它们也会经过其他线路,因为它们需要计数。我敢肯定这对你没有帮助,因为你很可能会陷入 IO 瓶颈。但你会有多个进程,允许你使用多个 CPU,如果这是你想要的。;-)

现在,如果如果你的所有行都具有相同的字节长度,那么你肯定可以进行真正的并行化。在这种情况下,你将使用“dd”提取每个“awk”进程的精确部分。你可以做类似的事情:

dd if=original.tsv bs=30 count=50000 skip=0 | cut -f3,4,5,6 | awk 'BEGIN { FS="\t" }; { print $2"\t"$1"\t"$3"\t"$4 }' > abridged01.tsv

dd if=original.tsv bs=30 count=50000 skip=50000 | cut -f3,4,5,6 | awk 'BEGIN { FS="\t" }; { print $2"\t"$1"\t"$3"\t"$4 }' > abridged02.tsv

dd if=original.tsv bs=30 count=50000 skip=100000 | cut -f3,4,5,6 | awk 'BEGIN { FS="\t" }; { print $2"\t"$1"\t"$3"\t"$4 }' > abridged03.tsv

其中 30 是每行的字节数。如果您的行的字节数不完全相同(这是最有可能的)如果您知道行块开始和结束的确切字节,您仍然可以使用 dd 来执行此操作。研究其参数。最后,如果您不知道块的开始和结束位置,可以使用额外的 awk 命令找出它们。但这会在您的文件中增加额外的完整读取。除非您将以不同的方式多次处理原始 .tsv 文件,否则您肯定会花费更多时间进行预处理(计算行块开始和结束的字节),然后进行处理(这可能会有一点好处,因为您肯定会遇到 IO 瓶颈),而不是简单地使用您已知的解决方案。

无论如何,现在您已经有了信息和选择。;-) 祝你好运!(y)

答案2

Fwiw,该split命令有一个选项,可以在将数据写入输出文件之前对其进行处理。因此,您可以有一个包含转换的--filter=./myscript.sh预处理脚本,例如,./myscript.sh

cut ... | awk '...' > $FILE

其中是(例如,...)$FILE生成的输出文件。或者,为了避免所有临时文件,只需连接到单个文件,splitxaa

cut ... | awk '...' >> abridged.tsv

然而,没有理由相信这会比不使用更快split

考虑到您正在进行“大数据”处理(以及这个问题最初提出后多少年),将这个 30GB 文件复制到 hdfs(或者,更确切地说,将数据最初放在那里并保存)并使用 apache hive 根据需要选择/格式化数据可能同样容易。

相关内容