使用多线程加载大型JSON文件/

时间:2015-06-22 14:13:20

标签: json jq

我正在尝试加载一个大的3 GB JSON文件。目前,使用JQ实用程序,我可以在近40分钟内加载整个文件。现在,我想知道如何在JQ中使用并行/多线程方法,以便在更短的时间内完成该过程。我正在使用v1.5

使用的命令:

{
  "results": [
    {
      "_id": "0000001",
      "body": {
        "party": {
          "related-parties": {},
          "general-info": {
            "last-update-ts": "2011-02-14T08:21:51.000-05:00",
            "full-name": "Ibercaja Gestion SGIIC SAPensiones Nuevas Oportunidades",
            "status": "ACTIVE",
            "last-update-user": "TS42922",
            "create-date": "2011-02-14T08:21:51.000-05:00",
            "classifications": {
              "classification": [
                {
                  "code": "PENS"
                }
              ]
            }
          },
          "xrefs": {
            "xref": [
              {
                "type": "LOCCU1",
                "id": "X00893X"
              },
              {
                "type": "ID",
                "id": "1012227139"
              }
            ]
          }
        }
      }
    },
    {
      "_id": "000002",
      "body": {
        "party": {
          "related-parties": {},
          "general-info": {
            "last-update-ts": "2015-05-21T15:10:45.174-04:00",
            "full-name": "Innova Capital Sp zoo",
            "status": "ACTIVE",
            "last-update-user": "jw74592",
            "create-date": "1994-08-31T00:00:00.000-04:00",
            "classifications": {
              "classification": [
                {
                  "code": "CORP"
                }
              ]
            }
          },
          "xrefs": {
            "xref": [
              {
                "type": "ULTDUN",
                "id": "144349875"
              },
              {
                "type": "AVID",
                "id": "6098743"
              },
              {
                "type": "LOCCU1",
                "id": "1001210218"
              },
              {
                "type": "ID",
                "id": "1001210218"
              },
              {
                "type": "BLMBRG",
                "id": "10009050"
              },
              {
                "type": "REG_CO",
                "id": "0000068508"
              },
              {
                "type": "SMCI",
                "id": "13159"
              }
            ]
          }
        }
      }
    }
  ]
}

我的数据:

from bs4 import BeautifulSoup
import urllib,sys
reload(sys)
sys.setdefaultencoding("utf-8")
r = urllib.urlopen('https://twitter.com/ndtv').read()
soup = BeautifulSoup(r)

有人可以帮助我在v1.5中使用哪个命令来实现并行/多线程。

2 个答案:

答案 0 :(得分:2)

以下是一种流式处理方法,假设您的3GB数据文件位于data.json,以下过滤器位于filter1.jq中:

  select(length==2)
| . as [$p, $v]
| {r:$p[1]}
| if   $p[2:6] == ["body","party","general-info","full-name"]       then .name = $v
  elif $p[2:6] == ["body","party","xrefs","xref"] and $p[7] == "id" then .id   = $v
  else  empty
  end      

使用

运行jq时
$ jq -M -c --stream -f filter1.jq data.json

jq将生成一个结果流,您需要的细节最少

{"r":0,"name":"Ibercaja Gestion SGIIC SAPensiones Nuevas Oportunidades"}
{"r":0,"id":"X00893X"}
{"r":0,"id":"1012227139"}
{"r":1,"name":"Innova Capital Sp zoo"}
{"r":1,"id":"144349875"}
{"r":1,"id":"6098743"}
{"r":1,"id":"1001210218"}
{"r":1,"id":"1001210218"}
{"r":1,"id":"10009050"}
{"r":1,"id":"0000068508"}
{"r":1,"id":"13159"}

您可以使用第二个filter2.jq

将其转换为所需的格式
foreach .[] as $i (
     {c: null, r:null, id:null, name:null}

   ; .c = $i
   | if .r != .c.r then .id=null | .name=null | .r=.c.r else . end   # control break
   | .id   = if .c.id == null   then .id   else .c.id   end
   | .name = if .c.name == null then .name else .c.name end

   ; [.id, .name]
   | if contains([null]) then empty else . end
   | join("~")
)

在使用

运行时消耗第一个过滤器的输出
$ jq -M -c --stream -f filter1.jq data.json | jq -M -s -r -f filter2.jq

并制作

X00893X~Ibercaja Gestion SGIIC SAPensiones Nuevas Oportunidades
1012227139~Ibercaja Gestion SGIIC SAPensiones Nuevas Oportunidades
144349875~Innova Capital Sp zoo
6098743~Innova Capital Sp zoo
1001210218~Innova Capital Sp zoo
1001210218~Innova Capital Sp zoo
10009050~Innova Capital Sp zoo
0000068508~Innova Capital Sp zoo
13159~Innova Capital Sp zoo

只需使用两个 jq 进程即可。如果需要更多并行性,可以使用记录号(r)来对数据进行分区并并行处理分区。例如,如果将中间输出保存到temp.json文件

$ jq -M -c --stream -f filter1.jq data.json > temp.json

然后您可以与

等过滤器并行处理temp.json
$ jq -M 'select(0==.r%3)' temp.json | jq -M -s -r -f filter2.jq > result0.out &
$ jq -M 'select(1==.r%3)' temp.json | jq -M -s -r -f filter2.jq > result1.out &
$ jq -M 'select(2==.r%3)' temp.json | jq -M -s -r -f filter2.jq > result2.out &

并在必要时将分区连接到最后的单个结果中。此示例使用3个分区,但如果需要更多并行性,则可以轻松地将此方法扩展到任意数量的分区。

GNU parallel也是不错的选择。如JQ Cookbook中所述,jq-hopkok's parallelism folder有一些很好的例子

答案 1 :(得分:0)

对于此大小的文件,您需要将文件流式传输并一次处理一个项目。首先寻找''结果':['然后使用一个名为'readItem'的函数,使用堆栈来匹配大括号,直到你的左大括号关闭,将每个字符附加到缓冲区,然后在关闭大括号后反序列化项目找到。

我推荐使用node.js + lodash作为实现语言。