Python从流中生成JSON文档

时间:2014-04-01 12:25:25

标签: python json ravendb

我有一个REST API(RavenDB's Query Streaming),它以JSON格式返回 lot 数据。加载到内存并一次解析是太多了:

问题在于,它不是“每行一个文档”,而是非常容易,它会在名为“Results”的字段中返回包含我们文档的单个字符串,如下所示:

{"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文档的最有效方法是什么?

2 个答案:

答案 0 :(得分:1)

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

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

答案 1 :(得分: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