使用GNU Parallel和Split

15
我正在向postgresql数据库加载一个相当庞大的文件。为此,我首先使用split将文件分成较小的文件(每个30GB),然后使用GNU Parallelpsql copy将每个较小的文件加载到数据库中。
问题是分割文件需要大约7小时的时间,然后它开始每个核心加载一个文件。我需要一种方法来告诉split在完成写入文件时打印文件名到标准输出,以便我可以将其管道传输到Parallel并在split完成写入后开始加载文件。类似于这样的东西:
split -l 50000000 2011.psv carga/2011_ | parallel ./carga_postgres.sh {}

我已经阅读了“split”手册,但没有找到任何信息。 有没有使用“split”或其他工具来完成这个任务的方法?

分割 --verbose 可以吗? - KevinDTimm
@KevinDTimm 详细选项会在开始创建文件时打印,而不是在完成时打印。 - Topo
因此,当它创建文件X2时,请开始解析文件X1 :) - KevinDTimm
@KevinDTimm 但我想避免需要额外的脚本来完成这个任务。 - Topo
2个回答

32
您可以让并行处理拆分:
<2011.psv parallel --pipe -N 50000000 ./carga_postgres.sh

请注意,手册建议使用--block而不是-N,这仍然会在记录分隔符处分割输入,默认情况下为\n,例如:
<2011.psv parallel --pipe --block 250M ./carga_postgres.sh

测试--pipe-N

这是一个测试,将100个数字序列分成5个文件:

seq 100 | parallel --pipe -N23 'cat > /tmp/parallel_test_{#}'

检查结果:

wc -l /tmp/parallel_test_[1-5]

输出:

 23 /tmp/parallel_test_1
 23 /tmp/parallel_test_2
 23 /tmp/parallel_test_3
 23 /tmp/parallel_test_4
  8 /tmp/parallel_test_5
100 total

parallel--pipe -N 50000000 选项会将 50000000 行发送到 carga_postgres.sh 的标准输入? - Topo
@Topo:是的,没错。我已经编辑了答案,以说明--pipe-N的工作原理。 - Thor
1
由于您的输入数据非常庞大,建议您考虑使用 --joblog、--resume 和 --resume-failed(需要版本20130222)选项。 - Ole Tange
@Topo:我也使用 zsh,但无法重现此错误。测试示例是否有效?您使用的 parallelzsh 版本是什么?如果在 zsh -f 下运行,是否有帮助? - Thor
并行正是我所需要的,我正在使用的机器不支持在分割时使用--filter,而且并行执行也非常棒! - Matt
显示剩余2条评论

3
如果您使用GNU split,则可以使用--filter选项进行此操作。

‘--filter=command’
使用此选项时,不仅会将内容写入每个输出文件中,还会通过管道将其写入指定的shell命令。命令应该使用$FILE环境变量,该变量为每次调用命令时设置为不同的输出文件名。

您可以创建一个shell脚本,在其中创建一个文件,并在最后以后台方式启动carga_postgres.sh。
#! /bin/sh

cat >$FILE
./carga_postgres.sh $FILE &

使用该脚本作为过滤器。
split -l 50000000 --filter=./filter.sh 2011.psv

在你的例子中,cat 的作用是将 split 通过 stdin 发送的每一行写入到文件 $FILE 中,然后将 $FILE 文件名传递给 carga_postgres 函数。 - Topo
@Topo 正确,split 命令将行发送到过滤器的标准输入。$FILE 是 split 命令选择的名称。当然,您可以自由地使用另一个唯一的名称。 - Olaf Dietsche
我一直在进行一些小测试(只需在每个文件中执行head -1),当我在过滤标志的末尾添加&时,split生成的文件为空,并且head命令不显示任何内容...但是如果我执行split而没有使用&,则生成的文件正常,head会打印到屏幕上...这是正确的行为还是我做了可怕的解释? - Topo
1
@Topo 我刚刚测试了一下,如果你使用&运行过滤器,stdin确实会从/dev/null重定向。但是如果你不使用&运行过滤器,则split将等待过滤器退出后才开始下一个过滤器。因此,似乎必须使用脚本版本才能并行运行carga_postgres.sh。我已经相应地更新了我的答案。 - Olaf Dietsche

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接