在Ruby中解析非常大的JSON文件的正确方法是什么?

时间:2018-10-18 13:58:32

标签: json ruby

我们如何在Ruby中解析json文件?

require 'json'

JSON.parse File.read('data.json')

如果文件很大并且我们不想立即将其加载到内存中怎么办?那我们怎么解析呢?

4 个答案:

答案 0 :(得分:5)

由于您说不想立即将其加载到内存中,因此也许按块执行此操作更适合您。您可以检查yajl-ffi宝石来达到此目的。从他们的优势:

对于较大的文档,我们可以使用IO对象将其流式传输到解析器中。我们仍然需要为解析的对象留出空间,但是文档本身永远不会被完全读取到内存中。

require 'yajl/ffi'
stream = File.open('/tmp/test.json')
obj = Yajl::FFI::Parser.parse(stream)

但是,当从磁盘或通过网络流式传输小型文档时,yajl-ruby gem将为我们提供最佳性能。

海量文档以小块的形式通过网络到达EventMachine receive_data循环,这是Yajl::FFI唯一适合的地方。在EventMachine::Connection子类中,我们可能具有:

def post_init
  @parser = Yajl::FFI::Parser.new
  @parser.start_document { puts "start document" }
  @parser.end_document   { puts "end document" }
  @parser.start_object   { puts "start object" }
  @parser.end_object     { puts "end object" }
  @parser.start_array    { puts "start array" }
  @parser.end_array      { puts "end array" }
  @parser.key            { |k| puts "key: #{k}" }
  @parser.value          { |v| puts "value: #{v}" }
end

def receive_data(data)
  begin
    @parser << data
  rescue Yajl::FFI::ParserError => e
    close_connection
  end
end

解析器接受JSON文档的大块并解析到可用缓冲区的末尾。传入更多数据将从先前状态恢复解析。当状态发生有趣的变化时,解析器会将该事件通知所有已注册的回调proc。

事件回调是我们可以进行有趣的数据过滤并将其传递给其他进程的地方。上面的示例仅打印状态更改,但是回调可能会寻找一个名为行的数组,并小批量处理这些行对象的集合。通过这种方式,可以在恒定的内存空间中处理通过网络流式传输的数百万行。

答案 1 :(得分:2)

您可以使用oj宝石

它提供了高效的Oj::Saj解析器。

文档在这里:http://www.ohler.com/oj/doc/Oj/Saj.html

答案 2 :(得分:1)

这并不是真正的“正确”方式,但是您可以使用Linux jq命令代替。这是我见过的最高效的json解析器。

result = %x{jq -r '.foo | .bar' #{input_json_file}}.strip

答案 3 :(得分:0)

我写了FastJsonparser gem https://github.com/anilmaurya/fast_jsonparser,它可以非常快速地解析JSON文件。

语法:

FastJsonparser.load(src)#src是json文件的源路径

尝试一下。