在我的数据流管道中,我将字段impressions_raw
设置为Long
对象中的com.google.api.services.bigquery.model.TableRow
:
在我的管道中,我再次阅读TableRow
。但是,我取代Long
而不是Integer
。
但是,如果我明确将值设置为大于Long
的{{1}}值,例如30亿,那么我会返回Integer.MAX_VALUE
!
似乎Dataflow SDK正在进行某种类型的检查优化。
因此,如果不进行丑陋的类型检查,应该如何以编程方式处理此问题? (也许我错过了一些明显的东西)
答案 0 :(得分:3)
感谢您的报告。不幸的是,这个问题是使用TableRow
的基础。我们强烈推荐下面的解决方案1:在您的管道中尽快转换离TableRow
。
杰克逊在TableRowJsonCoder
内对您存储这些值的TableRow
对象进行序列化和反序列化。杰克逊完全按照你所描述的行为 - 也就是说,对于这个班级来说:
class MyClass {
Object v;
}
它会将v = Long.valueOf(<number>)
{v: 30}
或{v: 3000000000}
的实例序列化。但是,在反序列化时,它将使用表示答案所需的位数来确定对象的类型。请参阅this SO post。
我想到了两种可能的解决方案,强烈建议使用解决方案1:
不要将TableRow
用作中间值。换句话说,尽快转换为POJO。这种混淆发生的关键原因是TableRow
基本上是Map<String, Object>
而杰克逊(或其他程序员)不知道你想要Long
回来。使用POJO,类型将是明确的。
关闭TableRow
的另一个好处是找到一个有效的编码器,比如AvroCoder
。因为TableRow
被编码并从JSON解码,所以编码既冗长又缓慢 - 混乱TableRow
将是CPU和I / O密集型。我希望您使用Avro编码的POJO可以看到比使用TableRow
个对象时更好的性能。
有关示例,请参阅LaneInfo
in TrafficMaxLaneFlow
。
编写可以处理两者的代码:
long numberToLong(@Nonnull Number n) {
return n.longValue();
}
long x = numberToLong((Number) row.get("field"));
Long numberToLong(@Nonnull Number n) {
if (n instanceof Long) {
// avoid a copy
return n;
}
return Long.valueOf(n.longValue());
}
Long x = numberToLong((Number) row.get("field"));
如果n
可能是null
,您可能需要对第二种变体进行额外检查。