2014-04-01 49 views
3

我有一个REST API(RavenDB's Query Streaming),它以JSON格式返回lot数据。这是太多加载到内存和解析一次去:Python从流中生成JSON文档

问题是,而不是'每行一个文件',这将使它很容易,它返回一个单一的字符串与我们的文件在一个名为“结果”,具体如下:

{"Results":[ 
    {"Name":"Hello World"} 
]} 

我真正想要做的是使用Python的请求库流,像这样的回应:

r = requests.get('.../streams/query/Raven/DocumentsByEntityName?query=', stream=True) 
for chunk in r.iter_content(chunk_size=512, decode_unicode=False): 
    print chunk 

但我想获得单独的JSON文件,以免必须解析整个响应。一次产生一个JSON文档最有效的方法是什么?

回答

1

json.load()有一个可选的object_pairs_hook参数,您可以使用它。这个想法是捕获每个内部的dict,从你的回调函数返回一个空的字典(或者可能是None),以避免在内存中建立巨大的数据结构。

请记住,这不是一个性能优化:在我的测试中(使用import simplejson as json),我发现尽管我可以节省内存,但使用钩子检查每个元素使得解析实际上会慢几倍。不过,如果你内存不足,那总比没有好。

+0

你能告诉我一个例子,说明如何才能生成{“Results”中的内部字典:[{}]}? – Aaron

0

以下是我目前正在处理的事情。我正在做的是匹配大括号({}),以便我可以输出只需内部的JSON文档,每行一个(请参阅:JSON Lines)。

这使我能够将输出流式传输到一个文本文件,以后我可以对其进行解码,而无需解码内存中的整个项目。

任何建议或优化将是最受欢迎的!

def yield_stream(url1 = '/streams/query/Raven/DocumentsByEntityName?query=', query1=''): 
    r = requests.get(conf.db + url1 + query1, auth=conf.db_auth, stream=True) 
    i = 0 
    is_doc = False 
    is_str = False 
    doc1 = [] 
    for chunk in r.iter_content(chunk_size=1024, decode_unicode=True): 
     for char in chunk: 
      if is_doc: 
       doc1.append(char) 

      if doc1[-2:-1] != ['\\'] and doc1[-1:] == ['"']: 
       is_str = not is_str 

      if char == '{' and not is_str: 
       i += 1 
       if i == 2: 
        doc1.append(char) 
        is_doc = True 

      if char == '}' and not is_str: 
       i -= 1 
       if i == 1: 
        yield ''.join(doc1) 
        doc1 = [] 
        is_doc = False