hansnow
V2EX  ›  问与答

超大 JSON 文件处理问题

  •  1
     
  •   hansnow · Apr 20, 2016 · 6882 views
    This topic created in 3858 days ago, the information mentioned may be changed or developed.

    背景

    这些超大的 JSON 文件来自 Cuckoo Sandbox 的 report ,主要内容是一系列的系统 API 调用,包含 API 名称和参数。这些 JSON 文件大小一般在几十~几百 MB 之间。

    需求

    • 将这些 API 调用做一个 distinct 操作,也就是找出每个文件里包含了哪几种 API
    • 判断一个 API 是否在某个 API 调用序列里

    我的尝试

    • 简单粗暴:用 Python 直接 json.load ,然后逐项将 API 名称添加到 set 里,实现去重的效果。这种做法的问题是超级占内存
    • ijson :为了解决 json.load 带来的内存占用问题,尝试使用了 ijson ,它可以以流的方式读取 JSON ,这样内存占用虽然下来了,但是速度真的不快
    • mongodb :也尝试了将一些比较小的 JSON 直接放到 mongodb 里面,这样一个 distinct 操作就能直接得到我要的结果,非常方便,后面即使添加需求也很容易操作。但是这样做有个问题,对于比较大的 JSON(>16MB),没办法放到 mongodb 里。

    文件示例

    一份55MB左右的JSON 链接: http://pan.baidu.com/s/1eRZevq6 密码: 2h95

    求教

    请问这种场景下有没有一个比较好的解决方案可以实现上面的需求?

    Supplement 1  ·  Apr 21, 2016
    目前又试了一种方法来解决第一个需求:
    cat report2.json| jq '.behavior.processes[0].calls[] | .api' | sort | uniq | wc -l

    性能:
    cat report2.json 0.00s user 0.05s system 2% cpu 1.834 total
    jq '.behavior.processes[0].calls[] | .api' 1.97s user 0.09s system 96% cpu 2.133 total
    sort 0.79s user 0.01s system 26% cpu 3.023 total
    uniq 0.11s user 0.00s system 3% cpu 3.028 total
    wc -l 0.00s user 0.00s system 0% cpu 3.028 total

    速度倒是挺快了,但是 jq 还是把整个文件装进了内存

    关于 jq : https://stedolan.github.io/jq/
    17 replies  •  2016-04-21 18:48:18 +08:00
    Kisesy
    Kisesy
    Apr 20, 2016
    1
    能先提供一份这样的文件吗?
    hansnow
    hansnow
    OP
    Apr 20, 2016
    2
    @Kisesy 已经添加到正文
    S23VqeW93WZLlm6s
    S23VqeW93WZLlm6s
    Apr 20, 2016
    3
    关注一波,我也有这样的问题
    blahgeek
    blahgeek
    Apr 20, 2016
    4
    google "json sax parser"看看
    yingjun424
    yingjun424
    Apr 21, 2016 via iPhone
    5
    有没有可能这样 将这个大文件先切分成若干个小文件 然后对每个小文件分别计算 最后将这些结果再综合计算…也就是 map reduce 的想法…这个只是拍脑袋想 但是可以往这方面想想…没必要一次性处理完
    anerevol
    anerevol
    Apr 21, 2016
    6
    用 swift 写了脚本跑了下, 55MB 文件处理内存占用 76M 的样子
    hpeng
    hpeng
    Apr 21, 2016 via iPhone
    7
    开始想到 Jackson 的 TreeNode 然后看了下内容,好吧 py
    kn007
    kn007
    Apr 21, 2016 via Android
    8
    Mark ,明天睡醒看解决方案
    iyaozhen
    iyaozhen
    Apr 21, 2016
    9
    这个需求挺有意思的,也有类似的场景。感谢楼主提供数据,有时间试试。
    ipconfiger
    ipconfiger
    Apr 21, 2016
    10
    貌似 json 没有流式处理的方法......... 按道理来说应该是可以的
    dapang1221
    dapang1221
    Apr 21, 2016 via Android
    11
    手机在线,还没看那个文件。。 json 能拆开么?拆成每个 api 一个 json ,或是按其他方式重新整理下,这样处理一遍扔进 mongodb 就能避免 16MB 大小问题了。而且这种系统的 api 也不频繁更新,弄一遍能用好久
    qiukun
    qiukun
    Apr 21, 2016 via Android
    12
    手写 dfa 。
    hansnow
    hansnow
    OP
    Apr 21, 2016
    13
    @dapang1221 整个 json 文件是一个大的 object ,貌似不是很容易分开
    lxy42
    lxy42
    Apr 21, 2016
    14
    我记得 Python 的 JSON 库在解析 json 时可以提供一个过滤的回调函数,这样就可以边解析边去重
    lxy42
    lxy42
    Apr 21, 2016❤️1
    15
    import json
    import time

    api_set = set()

    def object_hook(dct):
    if "api" in dct:
    api_set.add(dct['api'])
    return dct['api']
    return dct
    data = json.load(open("report2.json"), object_hook = object_hook)

    print 'api length: {}'.format(len(api_set))
    print
    for api in api_set:
    print api
    #time.sleep(10)

    =============
    测试的文件是你上传到百度网盘的那个, windows10 下用任务管理器查看 python 进程内存占用峰值 60M ,但马上降下来。速度应该还行,不知道是否满足需求,楼主可以试试。
    hansnow
    hansnow
    OP
    Apr 21, 2016
    17
    @qiukun 噗。。。完全不会的说
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Privacy   ·   Solana   ·   3299 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 46ms · UTC 10:08 · PVG 18:08 · LAX 02:08 · JFK 05:08
    ♥ Do have faith in what you're doing.