【问题标题】:efficient join >100 files高效加入 >100 个文件
【发布时间】:2019-05-29 20:20:11
【问题描述】:

我有一个包含超过 100 个制表符分隔文件的列表,包含 5-8 百万行和 16 列(始终以相同的顺序排列)。我需要从每个文件中提取 5 个特定列,包括一个标识符列。我的最终输出(以 3 个输入文件为例)应该是 4 个文件,包含以下列:

  • 输出 1:ID,VAR1
  • 输出 2:VAR2.1,VAR2.2,VAR2.3
  • 输出 3:VAR3.1,VAR3.2,VAR3.3
  • 输出4:VAR4.1,VAR4.2,VAR4.3

其中“.1”、“.2”和“.3”表示列分别来自第一个、第二个和第三个输入文件。

我的问题是输入文件包含部分重叠的 ID,我需要提取这些行的并集(即在一个输入文件中至少出现一次的所有 ID)。更准确地说,output1 应该包含所有输入文件的“ID”和“VAR1”列的并集。其余输出文件的行顺序应与 output1 相同。最后,任何给定输入文件中不存在的行应该在 output2、output3 和 output4 中用“NA”填充。

我正在使用 while 循环、awk 和 join 的组合来完成工作,但这需要相当长的时间。我想知道是否有更快的方法来完成这项工作,因为我必须使用不同的输入文件一遍又一遍地运行相同的脚本。

到目前为止我的脚本:

ID=1
VAR1=6
VAR2=9
VAR3=12
VAR4=16
while read FILE;do
    sort -k${ID},${ID} < ${FILE} | awk -v ID=${ID} -v VAR1=${VAR1} -v VAR2=${VAR2} -v VAR3=${VAR3} -v VAR4=${VAR4} 'BEGIN{OFS="\t"};{print $ID,$VAR1 > "tmp1";print ${ID},$VAR2 > "tmp2";print ${ID},$VAR3 > "tmp3";print ${ID},$VAR4 > "tmp4"}'
    awk 'FNR==NR{a[$1]=$1;next};{if(($1 in a)==0){print $0 > "tmp5"}}' output1 tmp1
    cat output1 tmp5 > foo && mv foo output1
    join -e "NA" -a1 -a2 -t $'\t' -1 1 -2 1 output2 -o auto tmp2 > bar2 && mv bar2 output2
    join -e "NA" -a1 -a2 -t $'\t' -1 1 -2 1 output3 -o auto tmp3 > bar3 && mv bar2 output3
    join -e "NA" -a1 -a2 -t $'\t' -1 1 -2 1 output4 -o auto tmp4 > bar4 && mv bar2 output4
    rm tmp?
done < files.list
sort -k1,1 output1 > foo && mv foo output1

最后一句话:我将cat 用于 output1,因为 VAR1 中相同 ID 的所有值在所有输入文件中都是相同的(我在预处理文件时已确保这一点)。所以我可以将尚未包含的行附加到 output1 的底部并对最终的输出文件进行排序

【问题讨论】:

  • 为什么要排序?
  • 好问题NEGR KITAEC 并检查bar2 &amp;&amp; mv bar2 output2 和下一行bar3 &amp;&amp; mv bar2 ...
  • ouptut 中的 cat ouptut1 tmp5 &gt; foo 是您原始脚本中的错误还是仅在这里?
  • 第一个awk 命令使用IDVAR1VAR2VAR3VAR4 作为输入变量。什么时候填满?
  • 您从哪里获得ID?这是第一列,VAR1 第二列?

标签: bash performance join merge


【解决方案1】:

首先,您必须弄清楚大部分时间都浪费在了哪里。你可以'echo "running X";时间 ./X` 并确保您没有尝试优化脚本的最快部分。

您可以简单地在后台并行运行三个连接 (cmd args ) &amp; 然后 wait 让它们全部完成。如果这需要 1 秒,而之前的 awk 部分需要 10 分钟,那么这将无济于事。

您也可以将wait 放在cat output 1 tmp5... 之前和最后一行sort -k1... 之前。为此,您必须以不同的方式命名临时文件并在joins 之前重命名它们。这个想法是在后台为第一个文件wait 生成三个并行连接的输入,然后重命名文件,在后台运行joins 并生成下一个输入。循环完成后,只需等待最后一个 joins 完成。如果 awk 部分消耗的 CPU 时间与 joins 相当,这将有所帮助。

HTH,您可以制作更复杂的并行执行场景。

【讨论】:

  • 感谢您的提示!实际上,占用大部分时间的是 while 循环内第一行中的 sort-command。我认为这比在joins 之前对单独的文件进行排序要快,但忘记了我可以并行执行这些操作。我现在并行运行 3 个 joins,其中 - 在每个并行运行中 - 首先提取所需的列,然后是 sort。这使我的脚本的运行时间减半
猜你喜欢
  • 2018-11-26
  • 2013-01-24
  • 2021-07-03
  • 1970-01-01
  • 2011-02-26
  • 1970-01-01
  • 2016-10-13
  • 1970-01-01
  • 2015-10-06
相关资源
最近更新 更多