Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/387.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
Java 使用模式自动检测写入BigQuery的数据流作业_Java_Google Bigquery_Google Cloud Dataflow_Database Schema_Apache Beam - Fatal编程技术网

Java 使用模式自动检测写入BigQuery的数据流作业

Java 使用模式自动检测写入BigQuery的数据流作业,java,google-bigquery,google-cloud-dataflow,database-schema,apache-beam,Java,Google Bigquery,Google Cloud Dataflow,Database Schema,Apache Beam,目前,我们正在寻找将原始数据转换为通用结构以供进一步分析的最佳方法。我们的数据是JSON文件,有些文件有更多的字段,有些文件有更少的字段,有些文件可能有数组,但一般来说,它的结构是相同的 为此,我正在尝试用Java构建ApacheBeam管道。我的所有管道都基于此模板: 第一种方法是将整个JSON作为字符串加载到一列中,然后使用转换为公共结构。这在这里有很好的描述: 第二种方法是将数据加载到适当的列中。因此,现在可以通过标准SQL查询数据。它还需要了解模式。可以通过控制台、UI和其他:,来检测它

目前,我们正在寻找将原始数据转换为通用结构以供进一步分析的最佳方法。我们的数据是JSON文件,有些文件有更多的字段,有些文件有更少的字段,有些文件可能有数组,但一般来说,它的结构是相同的

为此,我正在尝试用Java构建ApacheBeam管道。我的所有管道都基于此模板:

第一种方法是将整个JSON作为字符串加载到一列中,然后使用转换为公共结构。这在这里有很好的描述:

第二种方法是将数据加载到适当的列中。因此,现在可以通过标准SQL查询数据。它还需要了解模式。可以通过控制台、UI和其他:,来检测它,但是我没有找到任何关于如何通过Java和ApacheBeam管道实现这一点的信息

我分析过,若表已经创建,那个么它在并没有模式的情况下就不能工作,只有一个例外

正如我前面提到的,新文件可能会带来新字段,所以应该相应地更新模式

假设我有三个JSON文件:

1. { "field1": "value1" }
2. { "field2": "value2" }
3. { "field1": "value3", "field10": "value10" }
第一个创建新表,其中一个字段field1的类型为string。 所以我的桌子应该是这样的:

|field1  |
----------
|"value1"|
第二个也会这样做,但是添加新字段field2。现在我的桌子应该是这样的:

|field1  |field2  |
-------------------
|"value1"|null    |
-------------------
|null    |"value2"|
第三个JSON应该在模式中添加另一个字段field10,以此类推。真正的JSON文件可能有200个或更多字段。处理这种情况有多难


哪种方法更适合进行这种转换?

我做了一些测试,模拟了典型的自动检测模式:首先,为了简单起见,我运行了所有数据以构建所有可能字段和类型的映射。我使用管道跟踪已经看到的字段,并将其保存为PCollectionView。我可以使用这种方式,因为模式在管道构造时是未知的。请注意,此方法仅适用于批处理作业

首先,我创建了一些没有严格模式的虚拟数据,其中每一行可能包含也可能不包含任何字段:

PCollection输入=p .applyCreate数据,Create.of KV.of1,{\user\:\Alice\,\age\:\22\,\country\:\demank\}, 千伏1,{\income\:\1500\,\blood\:\A+}, KV.of1,{\food\:\菠萝比萨饼\,\age\:\44\}, KV.of1,{\user\:\Bob\,\movie\:\Inception\,\income\:\1350\} ; 我们将读取输入数据,构建数据中不同字段名的映射,并进行基本类型检查,以确定它是否包含整数或字符串。当然,如果需要的话,这可以扩展。请注意,之前创建的所有数据都分配给同一个键,以便将它们分组在一起,我们可以构建一个完整的字段列表,但这可能是性能瓶颈。我们将输出物化,以便将其用作辅助输入:

PCollectionView模式输入=输入 .applyBuild模式,ParDo.of new DoFn{ //包含字段类型对的映射 @状态模式 私有最终状态规范模式Aspec= StateSpecs.valueMapCoder.ofStringUtf8Coder.of、StringUtf8Coder.of; @过程元素 public void processElementProcessContext c, @StateIdschema值状态模式Aspec{ JSONObject消息=新建JSONObject.element.getValue; Map current=firstNonNullschemaSpec.read,新HashMap; //遍历字段 message.keySet.forEachkey-> { 对象值=message.getkey; if!current.containsKeykey{ 字符串类型=字符串; 试一试{ Integer.parseIntvalue.toString; 类型=整数; } 捕获异常{} //如果需要调试,请取消注释 //LOG.infokey:+key+value:+value+type:+type; c、 键的输出kV,类型; current.putkey,类型; schemaSpec.writecurrent; } }; } }.applySave as Map,View.asMap; 现在,我们可以使用前面的映射来构建包含BigQuery表架构的PCollectionView:

PCollectionView schemaView=p .applyStart,创建.ofStart .applyCreate Schema,ParDo.of new DoFn{ @过程元素 公共void processElementProcessContext c{ 映射schemaFields=c.sideInputschemaSideInput; 列表字段=新的ArrayList; 对于Map.Entry字段:schemaFields.entrySet { fields.addnew TableFieldSchema.setNamefield.getKey.setTypefield.getValue; //LOG.infokey:+field.getKey+type:+field.getValue; } TableSchema schema=新TableSchema.setfields字段; 字符串jsonSchema; 试一试{ jsonSchema=Transport.getJsonFactory.toStringschema; }捕捉异常{ 抛出新的RuntimeExceptionOne; } c、 项目ID的outputImmutableMap.ofPROJECT\u ID:DATASET\u NAME.dynamic\u bq\u schema,js onSchema; }}.带SideInputsChemaSideInput .applySave为Singleton,View.asSingleton; 相应地更改完全限定表名项目\u ID:DATASET\u name.dynamic\u bq\u schema

最后,在我们的管道中,我们读取数据,将其转换为TableRow,并使用.WithChemAfroMViewsChemaView将其写入BigQuery:

输入 .applyConvert到TableRow,ParDo.of New DoFn{ @过程元素 公共void processElementProcessContext c{ JSONObject消息=新建JSONObject.element.getValue; TableRow row=新的TableRow; message.keySet.forEachkey-> { 对象值=message.getkey; row.setkey,值; }; c、 输出; }} .apply BigQueryIO.writeTableRows .toPROJECT\u ID:DATASET\u NAME.dynamic\u bq\u schema .使用ChemaFromVIEWSCHEMAVIEW .withCreateDispositionBigQueryIO.Write.CreateDisposition.CREATE_(如果需要) .withWriteDispositionBigQueryIO.Write.WriteDisposition.Write\u追加; 完整代码

管道创建的BigQuery表架构:

以及由此产生的稀疏数据:


我做了一些测试,其中我模拟了典型的自动检测模式:首先,为了简单起见,我运行了所有数据,构建了所有可能字段的映射以及我刚才考虑的字符串或整数类型。我使用管道跟踪已经看到的字段,并将其保存为PCollectionView。我可以使用这种方式,因为模式在管道构造时是未知的。请注意,此方法仅适用于批处理作业

首先,我创建了一些没有严格模式的虚拟数据,其中每一行可能包含也可能不包含任何字段:

PCollection输入=p .applyCreate数据,Create.of KV.of1,{\user\:\Alice\,\age\:\22\,\country\:\demank\}, 千伏1,{\income\:\1500\,\blood\:\A+}, KV.of1,{\food\:\菠萝比萨饼\,\age\:\44\}, KV.of1,{\user\:\Bob\,\movie\:\Inception\,\income\:\1350\} ; 我们将读取输入数据,构建数据中不同字段名的映射,并进行基本类型检查,以确定它是否包含整数或字符串。当然,如果需要的话,这可以扩展。请注意,之前创建的所有数据都分配给同一个键,以便将它们分组在一起,我们可以构建一个完整的字段列表,但这可能是性能瓶颈。我们将输出物化,以便将其用作辅助输入:

PCollectionView模式输入=输入 .applyBuild模式,ParDo.of new DoFn{ //包含字段类型对的映射 @状态模式 私有最终状态规范模式Aspec= StateSpecs.valueMapCoder.ofStringUtf8Coder.of、StringUtf8Coder.of; @过程元素 public void processElementProcessContext c, @StateIdschema值状态模式Aspec{ JSONObject消息=新建JSONObject.element.getValue; Map current=firstNonNullschemaSpec.read,新HashMap; //遍历字段 message.keySet.forEachkey-> { 对象值=message.getkey; if!current.containsKeykey{ 字符串类型=字符串; 试一试{ Integer.parseIntvalue.toString; 类型=整数; } 捕获异常{} //如果需要调试,请取消注释 //LOG.infokey:+key+value:+value+type:+type; c、 键的输出kV,类型; current.putkey,类型; schemaSpec.writecurrent; } }; } }.applySave as Map,View.asMap; 现在,我们可以使用前面的映射来构建包含BigQuery表架构的PCollectionView:

PCollectionView schemaView=p .applyStart,创建.ofStart .applyCreate Schema,ParDo.of new DoFn{ @过程元素 公共void processElementProcessContext c{ 映射schemaFields=c.sideInputschemaSideInput; 列表字段=新的ArrayList; 对于Map.Entry字段:schemaFields.entrySet { fields.addnew TableFieldSchema.setNamefield.getKey.setTypefield.getValue; //LOG.infokey:+field.getKey+type:+field.getValue; } TableSchema schema=新TableSchema.setfields字段; 字符串jsonSchema; 试一试{ jsonSchema=Transport.getJsonFactory.toStringschema; }捕捉异常{ 抛出新的RuntimeExceptionOne; } c、 项目ID的outputImmutableMap:DATASET\u NAME.dynamic\u bq\u schema,jsonSchema; }}.带SideInputsChemaSideInput .applySave为Singleton,View.asSingleton; 相应地更改完全限定表名项目\u ID:DATASET\u name.dynamic\u bq\u schema

最后,在我们的管道中,我们读取数据,将其转换为TableRow,并使用.WithChemAfroMViewsChemaView将其写入BigQuery:

输入 .applyConvert到TableRow,ParDo.of New DoFn{ @过程元素 公共void processElementProcessContext c{ JSONObject消息=新建JSONObject.element.getValue; TableRow row=新的TableRow; message.keySet.forEachkey-> { 对象值=message.getkey; row.setkey,值; }; c、 输出; }} .apply BigQueryIO.writeTableRows .toPROJECT\u ID:DATASET\u NAME.dynamic\u bq\u schema .使用ChemaFromVIEWSCHEMAVIEW .withCreateDispositionBigQueryIO.Write.CreateDisposition.CREATE_(如果需要) .withWriteDispositionBigQueryIO.Write.WriteDisposition.Write\u追加; 完整代码

管道创建的BigQuery表架构:

以及由此产生的稀疏数据:


如果数据是基于模式avro、protobuf等序列化的,则可以在流作业中创建/更新表模式。。从这个意义上讲,它是预定义的,但仍在作为处理的一部分更新表架构。

如果数据是基于架构avro、protobuf等序列化的,则可以在流式处理作业中创建/更新表架构。。从这个意义上说,它是预定义的,但仍在作为处理的一部分更新表架构。

这是打算从TextIO保留为批处理,还是以后也希望在流模式下执行此操作。@RezaRokni我不确定,到BigQuery的流式插入不是免费的。因此,目前它将从FileIO进行批处理。请注意,您也可以通过选择FILE_LOADS方法和设置在流式管道中使用加载作业。withTriggeringFrequency是打算从TextIO保留为批处理,还是希望将来在流式模式下执行此操作。@RezaRokni我不确定,对BigQuery的流式插入不是免费的。因此,目前将从FileIO进行批处理。请注意,通过选择FILE_LOADS方法和设置,您也可以在流式管道中使用加载作业。通过TriggeringFrequency,在进行了大量研究和测试后,我们决定使用预定义的表模式。所以原始数据经过转换,输出总是与表模式匹配。不过,现在我明白了如何解决这类问题。很抱歉回答得太长了。在做了大量的研究和测试之后,我们决定使用预定义的表模式。所以原始数据经过转换,输出总是与表模式匹配。不过,现在我明白了如何解决这类问题。很抱歉回答得太长了。