使用jq,如何根据对象属性的值将对象的JSON流拆分为单独的文件?

使用jq,如何根据对象属性的值将对象的JSON流拆分为单独的文件?,json,bash,stream,jq,partitioning,Json,Bash,Stream,Jq,Partitioning,我有一个名为input.json的20GB+压缩文件,其中包含一个json对象流,如下所示: { "timestamp": "12345", "name": "Some name", "type": "typea" } { "timestamp": "12345", "name": "Some name", "type": "typea" } { "timestamp": "12345", "name": "Some name",

我有一个名为input.json的20GB+压缩文件,其中包含一个json对象流,如下所示:

{
    "timestamp": "12345",
    "name": "Some name",
    "type": "typea"
}
{
    "timestamp": "12345",
    "name": "Some name",
    "type": "typea"
}
{
    "timestamp": "12345",
    "name": "Some name",
    "type": "typeb"
}
我想将这个文件拆分为依赖于其type属性的文件:typea.json、typeb.json等,每个文件都包含自己的json对象流,这些对象只有匹配的type属性

对于较小的文件,我已经设法解决了这个问题,但是对于如此大的文件,我的AWS实例内存不足。由于我希望降低内存使用率,我知道我需要使用-stream,但我很难看到如何实现这一点

cat input.json | jq-c-stream'select.[0][0]==type |.[1]'将返回每个类型属性的值,但如何使用它过滤对象


任何帮助都将不胜感激

假设文件中的JSON对象相对较小(不超过几MB),则不需要使用相当复杂的-stream命令行选项,这主要是在输入是或包含单个庞大的JSON实体时需要的

然而,仍有若干选择有待作出。在中描述了主要的方法,这些方法是对jq的多通方法N或N+1调用,其中N是输出文件的数量,以及只涉及对jq的一次调用,然后调用诸如awk之类的程序来执行实际的文件分区的方法。每种方法都有其优缺点,但是如果可以接受读取输入文件N次,那么第一种方法可能更好

为了估计所需的总计算资源,最好测量运行jq empty input.json所使用的资源

从您的简短编写过程来看,您遇到的内存问题似乎主要是由于文件解压缩造成的。

使用jq拆分为NUL分隔的类型流、文档对,并使用本机bash 4.1或更高版本使用一组持久的文件描述符写入这些文档:

#!/usr/bin/env bash
case $BASH_VERSION in ''|[1-3].*|4.0*) echo "ERROR: Bash 4.1 needed" >&2; exit 1;; esac

declare -A output_fds=( )

while IFS= read -r -d '' type && IFS= read -r -d '' content; do
  if [[ ${output_fds[$type]} ]]; then  # already have a file handle for this output file?
    curr_fd=${output_fds[$type]}       # reuse it, then.
  else
    exec {curr_fd}>"$type.json"        # open a new output file...
    output_fds[$type]=$curr_fd         # and store its file descriptor for use.
  fi
  printf '%s\n' "$content" >&"$curr_fd"
done < <(jq -j '(.type) + "\u0000" + (. | tojson) + "\u0000"')

无可否认,这种方法每次读取的记录不会超过几个,每个记录可能有多个副本,因此只要记录大小合理,它就可以处理任意大的文件。

有多少种不同的类型?如果我们在一个过程中展开多个进程,那么需要打开多少个文件描述符?如果我们对每种类型进行一次传递,我们需要多少次传递?你真的不需要-这里是stream,顺便说一句。如果你的对象更大,但它们都足够小,可以单独处理。顺便说一句,这个输入没有错,根本不是有效的JSON。jq.,为您的示例输入提供了数据,但由于解析错误而失败:第2行第14列的文字无效。我能看到的唯一情况是,如果问题错误地表述了您的数据格式,并且对象位于其他较大的对象中,而不是位于顶层,则需要流。@CharlesDuffy大约有5-10种类型。谢谢你对-stream的帮助,看来我误解了它的用法。感谢您的帮助和有用资源的链接。文件的解压可能确实导致了内存问题,我会调查一下并报告。是的,内存问题是由解压过程引起的。我已经设法让它工作,现在将尝试您的方法和Charles Duffy的方法,以找出在我的用例中哪个更快。再次感谢您的帮助,我很乐意支持这个答案,但我的计时显示它比jq+awk解决方案慢10倍左右……在bash中执行文本处理时,awk后面的一个以10为基数的数量级正是我的目标,因为bash逐字符读取,而awk执行缓冲读取。也就是说,你认为这种性能差异是不可接受的;我认为这意味着我正在为正在使用的运行时编写接近最优的代码:我没有说不能接受。顺便说一句,对于较大的input.json,比率会变得更糟。对于大约80000个物体,我的测量值是17:1。这令人惊讶——我预计它至少比awk慢一个数量级;我不认为它会随着尺寸而变慢。你对这种关系有多确定?的确,到目前为止,我只仔细查看了两个输入文件,但两个文件中较大的文件只有~60MB,与OP的input.json相比,这一点显得微不足道。顺便说一下,17:1的比例是800K对象,而不是我输入错误的80K对象。