我有一个目录,里面有250万个小JSON文件。它在磁盘上有104 It。它们是多行文件。
我想从这些文件创建一组JSON数组,这样我就可以在合理的时间内使用mongoimport导入它们。文件大小不能超过16mb,但即使我设法将它们分成10个一组,我也会很高兴。
到目前为止,我可以使用这个以大约1000/分钟的速度一次完成一个:
for i in *.json; do mongoimport --writeConcern 0 --db mydb --collection all --quiet --file $i; done我想我可以使用" jq“来做这件事,但是我不知道如何让bash循环一次向jq传递10个文件。请注意,使用bash find会导致错误,因为文件太多。
使用jq,您可以使用--slurp创建数组,使用-c创建多行json单行。但是,我不知道如何将这两个命令合并为一个命令。
如果可能,请帮助解决问题的两个部分。
发布于 2017-01-18 20:40:56
这里有一种方法。为了说明这一点,我使用了awk,因为它可以小批量读取文件列表,并且能够执行jq和mongoimport。您可能需要进行一些调整,以使整个系统更加健壮,测试错误,等等。
这个想法要么是生成一个可以查看然后执行的脚本,要么是使用awk的system()命令直接执行命令。首先,让我们生成脚本:
ls *.json | awk -v group=10 -v tmpfile=json.tmp '
function out() {
print "jq -s . " files " > " tmpfile;
print "mongoimport --writeConcern 0 --db mydb --collection all --quiet --file " tmpfile;
print "rm " tmpfile;
files="";
}
BEGIN {n=1; files="";
print "test -r " tmpfile " && rm " tmpfile;
}
n % group == 0 {
out();
}
{ files = files " \""$0 "\"";
n++;
}
END { if (files) {out();}}
'一旦验证了它的有效性,您就可以执行生成的脚本,或者更改"print ...“要使用"system(....)“的行
使用jq生成脚本
下面是一个仅用于jq的脚本生成方法。由于文件数量非常大,下面的代码使用的是jq 1.5中才引入的功能,所以它的内存使用与上面的awk脚本类似:
def read(n):
# state: [answer, hold]
foreach (inputs, null) as $i
([null, null];
if $i == null then .[0] = .[1]
elif .[1]|length == n then [.[1],[$i]]
else [null, .[1] + [$i]]
end;
.[0] | select(.) );
"test -r json.tmp && rm json.tmp",
(read($group|tonumber)
| map("\"\(.)\"")
| join(" ")
| ("jq -s . \(.) > json.tmp", mongo("json.tmp"), "rm json.tmp") )调用:
ls *.json | jq -nRr --arg group 10 -f generate.jq发布于 2017-01-18 22:39:52
这是我想出来的。它似乎起作用了,正在以大约每秒80的速度导入到外部硬盘驱动器中。
#!/bin/bash
files=(*.json)
for((I=0;I<${#files[*]};I+=500)); do jq -c '.' ${files[@]:I:500} | mongoimport --writeConcern 0 --numInsertionWorkers 16 --db mydb --collection all --quiet;echo $I; done然而,有些是失败的。我已经导入了105k的文件,但只有98547个出现在mongo集合中。我想是因为有些文档大于16mb。
https://stackoverflow.com/questions/41718679
复制相似问题