从Dataflow中读取BigQuery表,其中的一个字段是“记录”和“重复”字段。所以我期望Java中的结果数据类型为List
但是,当我尝试遍历列表时,出现以下异常: java.lang.ClassCastException:java.util.LinkedHashMap无法转换为com.google.api.services.bigquery.model.TableRow < / em>
表架构看起来像这样:
{
"id": "my_id",
"values": [
{
"nested_record": "nested"
}
]
}
迭代值的代码如下所示:
String id = (String) row.get("id");
List<TableRow> values = (List<TableRow>) row.get("values");
for (TableRow nested : values) {
// more logic
}
在循环开始的地方抛出异常。 这里明显的解决方法是将值强制转换为LinkedHashMaps的列表,但这感觉不对。 有谁知道为什么数据流会为嵌套的“记录”引发此类错误?
答案 0 :(得分:0)
当我尝试使用Google Cloud DataFlow从BigQuery读取嵌套表时,遇到了同样的ClassCastException
。最后通过将TableRow
强制转换为不同的数据结构来解决,具体取决于我使用的是哪个DataFlow运行器:
DirectRunner
:投射到LinkedHashMap
DataflowRunner
:强制转换为TableRow
。 示例:
Object valuesList = row.get("values");
// DirectRunner
for (TableRow v : (List<LinkedHashMap>) valuesList) {
String name = v.get("name");
String age = v.get("age");
}
// DataflowRunner
for (TableRow v : (List<TableRow>) valuesList) {
String name = v.get("name");
String age = v.get("age");
}
答案 1 :(得分:0)
造成这种情况的根本原因是DirectRunner在步骤之间执行编码往返,这通常不在Dataflow中执行。作为Table字段访问重复记录(或任何记录)将在这两个运行程序上成功执行,因为TableRow实现了Map接口。 记录被读取为“ TableRow”类型,但是在对它们进行编码时,它们被编码为简单的JSON映射。因为JSON编码器无法识别地图的字段类型,所以它将记录反序列化为简单的地图类型。
TableRow是一个Map,因此您可以将两种情况都视为Map:
String id = (String) row.get("id");
List<? extends Map> values = row.get("values");
for (Map nested : values) {
// more logic
}