在我的数据流管道中,我将impressions_raw
字段设置为Long
对象中的com.google.api.services.bigquery.model.TableRow
:
在我的管道中,进一步读回TableRow
。但是我取回了Long
而不是Integer
。
但是,如果我将值显式设置为大于Long
的Integer.MAX_VALUE
值(例如30亿),那么我将获得Long
!
似乎Dataflow SDK正在后台进行某种类型检查优化。
因此,在不进行难看的类型检查的情况下,应该如何以编程的方式处理这一问题? (也许我错过了一些明显的事情)
最佳答案
感谢您的报告。不幸的是,这个问题对于TableRow
的使用是根本的。我们强烈建议您使用以下解决方案1:在您的管道中尽快从TableRow
转换为。
用于存储这些值的TableRow
对象由 TableRowJsonCoder
内部的Jackson进行了序列化和反序列化。 jackson 完全具有您正在描述的行为-也就是说,对于此类:
class MyClass {
Object v;
}
它将使用
v = Long.valueOf(<number>)
或{v: 30}
序列化实例。但是,在反序列化时,它将使用表示答案所需的位数确定对象的类型。参见this SO post。我想到了两种可能的解决方案,强烈建议使用解决方案1:
{v: 3000000000}
用作中间值。换句话说,请尽快转换为POJO。发生这种类型混合的主要原因是TableRow
本质上是TableRow
,而Jackson(或其他编码器)无法知道您想要Map<String, Object>
。使用POJO,类型将很清楚。关闭
Long
的另一个好处是可以获得高效的编码器,例如TableRow
。由于AvroCoder
是从JSON编码和解码的,因此编码既冗长又缓慢-改组TableRow
将占用大量CPU和I/O。我希望通过Avro编码的POJO可以看到比传递TableRow
对象更好的性能。有关示例,请参见
TableRow
in LaneInfo
。 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"));
如果
TrafficMaxLaneFlow
可能是n
,则您可能需要对第二种变体进行其他检查。 关于google-cloud-platform - 数据流混合整数和长整型,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/33622227/