Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/json/15.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 将包含多个表的250GB JSON文件拆分为拼花地板_Python_Json_Dask_Parquet - Fatal编程技术网

Python 将包含多个表的250GB JSON文件拆分为拼花地板

Python 将包含多个表的250GB JSON文件拆分为拼花地板,python,json,dask,parquet,Python,Json,Dask,Parquet,我有一个JSON文件,格式如下: { "Table1": { "Records": [ { "Key1Tab1": "SomeVal", "Key2Tab1": "AnotherVal" }, {

我有一个JSON文件,格式如下:

{
    "Table1": {
        "Records": [
            {
                "Key1Tab1": "SomeVal",
                "Key2Tab1": "AnotherVal"
            },
            {
                "Key1Tab1": "SomeVal2",
                "Key2Tab1": "AnotherVal2"
            }
        ]
    },
    "Table2": {
        "Records": [
            {
                "Key1Tab1": "SomeVal",
                "Key2Tab1": "AnotherVal"
            },
            {
                "Key1Tab1": "SomeVal2",
                "Key2Tab1": "AnotherVal2"
            }
        ]
    }
}
根键是SQL数据库中的表名,对应的值是行。 我想将JSON文件拆分为单独的拼花文件,每个拼花文件代表一个表。 即
表1.拼花
表2.拼花

最大的问题是文件的大小阻止我将其加载到内存中。 因此,我尝试使用dask.bag来适应文件的嵌套结构

import dask.bag as db
from dask.distributed import Client
client = Client(n_workers=4)

lines = db.read_text("filename.json")

但是用
行评估输出。take(4)
表明dask无法正确读取新行

('{\n', '    "Table1": {\n', '        "Records": [\n', '            {\n')
我试图寻找具体问题的解决方案,但运气不佳

是否有可能使用dask解决拆分问题,或者是否有其他工具可以完成此工作?

如建议,请尝试此方法

这可能足够了,但我不确定如果没有足够的内存将整个生成的数据帧存储在内存中,它将如何运行

导入dask.dataframe作为dd
从dask.distributed导入客户端
client=client()
df=dd.read_json(“filename.json”)
df.to_parquet(“filename.parquet”,engine='pyarrow')
文件


如果Dask在单个系统上不分块处理文件(它可能不喜欢这样做,因为JSON以这种方式解析显然不友好..尽管很遗憾,我无法访问我的测试系统来验证这一点),并且系统内存无法处理这个巨大的文件,您可以通过创建一个大交换文件来扩展系统内存和磁盘空间

请注意,这将创建一个约300G的文件(增加
count
字段以获取更多信息),与内存相比,速度可能会非常慢(但可能仍然足够快,满足您的需要,特别是如果是一次性的)

#创建和配置交换文件
dd if=/dev/zero of=swapfile.img bs=10M计数=30000状态=进度
chmod 600 swapfile.img
mkswap swapfile.img
swapon swapfile.img
#
#运行内存贪婪任务
# ...
#确保流程已退出
#
#禁用并删除交换文件以回收磁盘空间
swapoff swapfile.img#可能会挂很长时间
rm swapfile.img

问题是,DASK默认情况下会在新行字符上拆分文件,并且不能保证这不会在一个表的中间。事实上,即使您做对了,您仍然需要操纵结果文本,为每个分区生成完整的JSON对象

_.compute()

[{'Table1': {'Records': [{'Key1Tab1': 'SomeVal', 'Key2Tab1': 'AnotherVal'},
    {'Key1Tab1': 'SomeVal2', 'Key2Tab1': 'AnotherVal2'}]}},
 {},
 {'Table2': {'Records': [{'Key1Tab1': 'SomeVal', 'Key2Tab1': 'AnotherVal'},
    {'Key1Tab1': 'SomeVal2', 'Key2Tab1': 'AnotherVal2'}]}},
 {},
 {},
 {}]
例如:

def myfunc(x):
    x = "".join(x)
    if not x.endswith("}"):
        x = x[:-2] + "}"
    if not x.startswith("{"):
        x = "{" + x
    return [json.loads(x)]

db.read_text('temp.json', 
             linedelimiter="\n    },\n", 
             blocksize=100).map_partitions(myfunc)
在本例中,我特意将blocksize设置为小于每个部分,以演示:每个分区将获得一个JSON对象,或者什么都没有

_.compute()

[{'Table1': {'Records': [{'Key1Tab1': 'SomeVal', 'Key2Tab1': 'AnotherVal'},
    {'Key1Tab1': 'SomeVal2', 'Key2Tab1': 'AnotherVal2'}]}},
 {},
 {'Table2': {'Records': [{'Key1Tab1': 'SomeVal', 'Key2Tab1': 'AnotherVal'},
    {'Key1Tab1': 'SomeVal2', 'Key2Tab1': 'AnotherVal2'}]}},
 {},
 {},
 {}]

当然,在您的情况下,您可以立即对JSON执行某些操作,而不是返回它,或者您可以
映射到下一个编写函数。

处理大型文件时,成功的关键是将数据作为流处理,即在类似过滤器的程序中处理

JSON格式很容易解析。下面的程序逐字符读取输入字符(I/O应为bufferred),并将顶级JSON对象切割为单独的对象。它正确地遵循数据结构,而不是格式

演示程序只打印“--下一个输出文件--”,在这里应该实现真正的输出文件切换。空格剥离是作为奖励实现的

import collections

OBJ = 'object'
LST = 'list'

def out(ch):
    print(ch, end='')

with open('json.data') as f:
    stack = collections.deque(); push = stack.append; pop = stack.pop
    esc = string = False
    while (ch := f.read(1)):
        if esc:
            esc = False
        elif ch == '\\':
            esc = True
        elif ch == '"':
            string = not string
        if not string:
            if ch in {' ', '\t', '\r', '\n'}:
                continue
            if ch == ',':
                if len(stack) == 1 and stack[0] == OBJ:
                    out('}\n')
                    print("--- NEXT OUTPUT FILE ---")
                    out('{')
                    continue
            elif ch == '{':
                push(OBJ)
            elif ch == '}':
                if pop() is not OBJ:
                    raise ValueError("unmatched { }")
            elif ch == '[':
                push(LST)
            elif ch == ']':
                if pop() is not LST:
                    raise ValueError("unmatched [ ]")
        out(ch)
以下是我的testfile的示例输出:

{"key1":{"name":"John","surname":"Doe"}}
--- NEXT OUTPUT FILE ---
{"key2":"string \" ] }"}
--- NEXT OUTPUT FILE ---
{"key3":13}
--- NEXT OUTPUT FILE ---
{"key4":{"sub1":[null,{"l3":true},null]}}
原始文件是:

{
    "key1": {
        "name": "John",
        "surname": "Doe"
    },  
    "key2": "string \" ] }", "key3": 13, 
    "key4": {
        "sub1": [null, {"l3": true}, null]
    }   
}

这种风格的东西可能是一个很好的中间解决方案(尽管更大的块大小,比如2x最大的db对象可能更合适,以防止一个对象出现在边界中)。。或者是一个具有精确的自定义解决方案—一旦文本块正确,您就可以处理数据,但这是完成工作最方便的方式。
df=dd.read_json(“filename.json”)
确实可以一次性读取整个文件;唯一的例外是,如果您有行分隔的JSON,情况并非如此。