V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
hansnow
V2EX  ›  问与答

超大 JSON 文件处理问题

  •  1
     
  •   hansnow · 2016-04-20 22:10:20 +08:00 · 6210 次点击
    这是一个创建于 3157 天前的主题,其中的信息可能已经有所发展或是发生改变。

    背景

    这些超大的 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

    求教

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

    第 1 条附言  ·  2016-04-21 11:35:24 +08:00
    目前又试了一种方法来解决第一个需求:
    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 条回复    2016-04-21 18:48:18 +08:00
    Kisesy
        1
    Kisesy  
       2016-04-20 22:14:05 +08:00
    能先提供一份这样的文件吗?
    hansnow
        2
    hansnow  
    OP
       2016-04-20 22:19:46 +08:00
    @Kisesy 已经添加到正文
    WittBulter
        3
    WittBulter  
       2016-04-20 22:33:04 +08:00
    关注一波,我也有这样的问题
    blahgeek
        4
    blahgeek  
       2016-04-20 22:50:44 +08:00
    google "json sax parser"看看
    yingjun424
        5
    yingjun424  
       2016-04-21 00:15:45 +08:00 via iPhone
    有没有可能这样 将这个大文件先切分成若干个小文件 然后对每个小文件分别计算 最后将这些结果再综合计算…也就是 map reduce 的想法…这个只是拍脑袋想 但是可以往这方面想想…没必要一次性处理完
    anerevol
        6
    anerevol  
       2016-04-21 00:50:45 +08:00
    用 swift 写了脚本跑了下, 55MB 文件处理内存占用 76M 的样子
    hpeng
        7
    hpeng  
       2016-04-21 01:06:27 +08:00 via iPhone
    开始想到 Jackson 的 TreeNode 然后看了下内容,好吧 py
    kn007
        8
    kn007  
       2016-04-21 01:34:43 +08:00 via Android
    Mark ,明天睡醒看解决方案
    iyaozhen
        9
    iyaozhen  
       2016-04-21 01:49:17 +08:00
    这个需求挺有意思的,也有类似的场景。感谢楼主提供数据,有时间试试。
    ipconfiger
        10
    ipconfiger  
       2016-04-21 02:08:56 +08:00
    貌似 json 没有流式处理的方法......... 按道理来说应该是可以的
    dapang1221
        11
    dapang1221  
       2016-04-21 02:17:45 +08:00 via Android
    手机在线,还没看那个文件。。 json 能拆开么?拆成每个 api 一个 json ,或是按其他方式重新整理下,这样处理一遍扔进 mongodb 就能避免 16MB 大小问题了。而且这种系统的 api 也不频繁更新,弄一遍能用好久
    qiukun
        12
    qiukun  
       2016-04-21 10:15:47 +08:00 via Android
    手写 dfa 。
    hansnow
        13
    hansnow  
    OP
       2016-04-21 11:32:37 +08:00
    @dapang1221 整个 json 文件是一个大的 object ,貌似不是很容易分开
    lxy42
        14
    lxy42  
       2016-04-21 12:36:43 +08:00
    我记得 Python 的 JSON 库在解析 json 时可以提供一个过滤的回调函数,这样就可以边解析边去重
    lxy42
        15
    lxy42  
       2016-04-21 13:59:55 +08:00   ❤️ 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 ,但马上降下来。速度应该还行,不知道是否满足需求,楼主可以试试。
    lxy42
        16
    lxy42  
       2016-04-21 14:06:55 +08:00
    hansnow
        17
    hansnow  
    OP
       2016-04-21 18:48:18 +08:00
    @qiukun 噗。。。完全不会的说
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   4960 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 32ms · UTC 05:48 · PVG 13:48 · LAX 21:48 · JFK 00:48
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.