【问题标题】:Dealing with a JSON object too big to fit into memory处理太大而无法放入内存的 JSON 对象
【发布时间】:2014-01-08 12:34:03
【问题描述】:

我有一个 Firebase 数据库的转储,它表示存储在 JSON 中的用户表。我想对其进行一些数据分析,但问题是它太大而无法完全加载到内存中并使用纯 JavaScript(或_ 和类似库)进行操作。

到目前为止,我一直在使用 JSONStream 包来处理我的小块数据(它为 JSON 转储中的每个用户调用一次回调)。

我现在遇到了一个障碍,因为我想过滤我的用户 ID 根据他们的价值。我试图回答的“问题”是“哪些用户 x”的形式,而之前我只是问“有多少用户 x”,并不需要知道他们是谁。

数据格式如下:

{
    users: {
        123: {
            foo: 4
        },
        567: {
            foo: 8
        }
    }
}

我要做的基本上是根据foo的值获取用户ID(上面的123567)。现在,如果这是一个小列表,那么使用 _.each 之类的东西来迭代键和值并提取我想要的键将是微不足道的。

不幸的是,因为它不适合无法工作的内存。使用 JSONStream,我可以使用 var parser = JSONStream.parse('users.*'); 对其进行迭代,并将其传递到一个处理它的函数中,如下所示:

var stream = fs.createReadStream('my.json');

stream.pipe(parser);

parser.on('data', function(user) {
    // user is equal to { foo: bar } here
    // so it is trivial to do my filter
    // but I don't know which user ID owns the data
});

但问题是我无法访问代表我传递给JSONStream.parse 的星号通配符的密钥。也就是说,我不知道{ foo: bar}是代表用户123还是用户567

问题是双重的:

  1. 如何从回调中获取当前路径?
  2. 有没有更好的方法来处理这个太大而无法放入内存的 JSON 数据?

【问题讨论】:

  • 1.你根本做不到。永远不会发生(使用您当前的结构)。为什么不将此 JSON 放入实际数据库(例如 MySQL)并实际查询它以进行分析?
  • 不能什么?是否有什么东西使得访问路径在技术上比数据更不可行?
  • 在您的回调中,正如您所了解的,没有path,只有数据。您没有上下文,并且 JSON 字符串中的“子”对象不知道它来自何处。
  • 我相信将它放入 MySQL 时会遇到同样的问题,我需要使用 JSONStream 来解析它(因为它仍然不适合内存)并且需要用户 ID将其存储到关系数据库中。
  • 两个问题 - 1) 为什么你不能访问 * 键和 2) 你有什么样的内存可用/文件有多大?如果它是从数据库中转储的,那么它肯定可以导入到数据库中。 - 我的错,我刚刚注意到 * 键在 JSON 流中是如何工作的,现在我明白了。

标签: javascript json node.js firebase jsonstream


【解决方案1】:

我继续编辑 JSONStream 以添加此功能。

如果有人遇到此问题并想以类似方式对其进行修补,您可以替换之前的line 83

stream.queue(this.value[this.key])

用这个:

var ret = {};
ret[this.key] = this.value[this.key];

stream.queue(ret);

在原始问题的代码示例中,user 在回调中等于 { foo: bar } 现在将是 { uid: { foo: bar } }

由于这是一项重大更改,我没有将拉取请求提交回原始项目,但我确实将其留在问题中,以防他们将来想为此添加标志或选项。

【讨论】:

  • 实现这一点的一种方法是在每次迭代时维护当前路径,这样您还可以返回包含 JSON 对象完整路径的字符串,而不是仅返回最后一个键名.
  • 是的,我认为这可能是首选。我对 Node 的 Stream 类不够熟悉,无法弄清楚如何做到这一点,但理想情况下,回调将采用 2 个参数,第一个是数据,第二个是到达它所需的路径段数组原始 JSON(例如 ['users', '123'])。这样您就可以轻松获取当前深度、任意数量的通配符等信息。
  • 看起来我的建议不太现实,因为 JSONStream 是……一个流,data 处理程序必须只管理一个参数,而不是两个。避免这种情况的一种方法是返回一个对象{value: {...}, path: ''},但这会破坏向后兼容性。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-18
  • 2011-09-09
  • 2016-02-08
  • 2014-10-11
  • 1970-01-01
相关资源
最近更新 更多