如何在python中编写可拆分的DoFn-在apache beam中将json转换为ndjson

如何在python中编写可拆分的DoFn-在apache beam中将json转换为ndjson,json,google-cloud-dataflow,apache-beam,ndjson,Json,Google Cloud Dataflow,Apache Beam,Ndjson,我在GCS中有一个json格式的大数据集,需要加载到BigQuery中。 问题在于json数据不是存储在NdJson中,而是存储在几个大的json文件中,其中json中的每个键实际上应该是json本身的一个字段 例如,以下Json: { "johnny": { "type": "student" }, "jeff": { "type": "teacher" } } 应转换为 [ { "name": "johnny", "type": "s

我在GCS中有一个json格式的大数据集,需要加载到BigQuery中。 问题在于json数据不是存储在NdJson中,而是存储在几个大的json文件中,其中json中的每个键实际上应该是json本身的一个字段

例如,以下Json:

{
  "johnny": {
    "type": "student"
  }, 
  "jeff": {
    "type": "teacher"
  }
}
应转换为

[ 
  {
    "name": "johnny",
    "type": "student"
  }, 
  {
    "name": "jeff",
    "type": "teacher"
  }
]
我试图通过Apache Beam通过Google Data Flow解决这个问题,但性能非常糟糕,因为ech“Worker”需要做很多工作:

class JsonToNdJsonDoFn(beam.DoFn):
    def __init__(self, pk_field_name):
        self.__pk_field_name = pk_field_name

    def process(self, line):
        for key, record in json.loads(line).items():
            record[self.__pk_field_name] = key
            yield record

我知道这可以通过将其实现为一个来解决,但是Python中的实现示例并不十分清楚。我应该如何将此DoFn构建为可拆分的,以及如何将其用作管道的一部分?

您需要一种方法来指定要处理json文件的部分范围。例如,它可以是一个字节范围

这是一个很好的例子。比如:

类MyJsonReader(DoFn):
def进程(文件名,tracker=DoFn.RestrictionTrackerParam)
使用fileio.ChannelFactory.open(文件名)作为文件:
开始,停止=跟踪器。当前\u限制()
#搜索起始偏移处或之后开始的第一个块。
file.seek(开始)
下一个\u记录\u开始=查找下一个\u记录(文件,开始)
启动时:
#声明当前记录的位置
如果不是跟踪器,请尝试索赔(下一个记录开始):
#超出当前限制范围-我们完成了。
回来
#start将指向已读取记录的结尾
记录,开始=读取记录(文件,下一个记录,开始)
产量记录
def get_初始_限制(自身、文件名):
返回值(0,fileio.ChannelFactory.size_,单位为字节(文件名))

然而,json并没有明确的记录边界,所以如果您的工作必须从字节548开始,就没有明确的方法来告诉您要移动多少。如果文件就是您所拥有的,那么您可以跳过字节,直到看到模式
”:{
。然后从
{

开始读取json对象。您需要一种方法来指定json文件的部分处理范围。例如,它可以是字节范围

这是一个很好的例子。比如:

类MyJsonReader(DoFn):
def进程(文件名,tracker=DoFn.RestrictionTrackerParam)
使用fileio.ChannelFactory.open(文件名)作为文件:
开始,停止=跟踪器。当前\u限制()
#搜索起始偏移处或之后开始的第一个块。
file.seek(开始)
下一个\u记录\u开始=查找下一个\u记录(文件,开始)
启动时:
#声明当前记录的位置
如果不是跟踪器,请尝试索赔(下一个记录开始):
#超出当前限制范围-我们完成了。
回来
#start将指向已读取记录的结尾
记录,开始=读取记录(文件,下一个记录,开始)
产量记录
def get_初始_限制(自身、文件名):
返回值(0,fileio.ChannelFactory.size_,单位为字节(文件名))

但是,json没有明确的记录边界,因此如果您的工作必须从字节548开始,则没有明确的方法来确定要移动多少。如果文件实际上就是您在那里拥有的,那么您可以跳过字节,直到您看到模式
:{
。然后从
开始读取json对象{

您的示例只更改了不太有用的MyJsonReader的AvroReader您的示例只更改了不太有用的MyJsonReader的AvroReader