2014-04-01 82 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