hansnow
V2EX  ›  问与答

超大 JSON 文件处理问题

  •  1
     
  •   hansnow · Apr 20, 2016 · 6618 views
    This topic created in 3693 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
        1
    Kisesy  
       Apr 20, 2016
    能先提供一份这样的文件吗?
    hansnow
        2
    hansnow  
    OP
       Apr 20, 2016
    @Kisesy 已经添加到正文
    WittBulter
        3
    WittBulter  
       Apr 20, 2016
    关注一波,我也有这样的问题
    blahgeek
        4
    blahgeek  
       Apr 20, 2016
    google "json sax parser"看看
    yingjun424
        5
    yingjun424  
       Apr 21, 2016 via iPhone
    有没有可能这样 将这个大文件先切分成若干个小文件 然后对每个小文件分别计算 最后将这些结果再综合计算…也就是 map reduce 的想法…这个只是拍脑袋想 但是可以往这方面想想…没必要一次性处理完
    anerevol
        6
    anerevol  
       Apr 21, 2016
    用 swift 写了脚本跑了下, 55MB 文件处理内存占用 76M 的样子
    hpeng
        7
    hpeng  
       Apr 21, 2016 via iPhone
    开始想到 Jackson 的 TreeNode 然后看了下内容,好吧 py
    kn007
        8
    kn007  
       Apr 21, 2016 via Android
    Mark ,明天睡醒看解决方案
    iyaozhen
        9
    iyaozhen  
       Apr 21, 2016
    这个需求挺有意思的,也有类似的场景。感谢楼主提供数据,有时间试试。
    ipconfiger
        10
    ipconfiger  
       Apr 21, 2016
    貌似 json 没有流式处理的方法......... 按道理来说应该是可以的
    dapang1221
        11
    dapang1221  
       Apr 21, 2016 via Android
    手机在线,还没看那个文件。。 json 能拆开么?拆成每个 api 一个 json ,或是按其他方式重新整理下,这样处理一遍扔进 mongodb 就能避免 16MB 大小问题了。而且这种系统的 api 也不频繁更新,弄一遍能用好久
    qiukun
        12
    qiukun  
       Apr 21, 2016 via Android
    手写 dfa 。
    hansnow
        13
    hansnow  
    OP
       Apr 21, 2016
    @dapang1221 整个 json 文件是一个大的 object ,貌似不是很容易分开
    lxy42
        14
    lxy42  
       Apr 21, 2016
    我记得 Python 的 JSON 库在解析 json 时可以提供一个过滤的回调函数,这样就可以边解析边去重
    lxy42
        15
    lxy42  
       Apr 21, 2016   ❤️ 1
    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
        17
    hansnow  
    OP
       Apr 21, 2016
    @qiukun 噗。。。完全不会的说
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Solana   ·   3850 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 87ms · UTC 00:54 · PVG 08:54 · LAX 17:54 · JFK 20:54
    ♥ Do have faith in what you're doing.