混合 Integer 和 Long 类型的数据流
Dataflow mixing Integer & Long types
在我的 Dataflow 管道中,我将字段 impressions_raw
设置为 com.google.api.services.bigquery.model.TableRow
对象中的 Long
:
在我的管道中,我读回了 TableRow
。但是我得到的不是 Long
,而是 Integer
.
但是,如果我明确将值设置为大于 Integer.MAX_VALUE
的 Long
值,例如 30 亿,那么我会得到一个 Long
!
Dataflow SDK 似乎在幕后进行某种类型检查优化。
那么,如果不进行丑陋的类型检查,应该如何以编程方式处理这个问题? (也许我错过了一些明显的东西)
感谢您的报告。不幸的是,这个问题是使用 TableRow
的基础。我们强烈推荐下面的解决方案 1:在您的管道中尽快从 TableRow
转换。
您存储这些值的 TableRow
对象由 Jackson 在 TableRowJsonCoder
中序列化和反序列化。 Jackson 具有您所描述的行为——也就是说,为此 class:
class MyClass {
Object v;
}
它会将 v = Long.valueOf(<number>)
的实例序列化为 {v: 30}
或 {v: 3000000000}
。然而,在反序列化时,它将使用表示答案所需的位数来确定对象的类型。参见 this SO post。
想到了两种可能的解决方案,强烈推荐解决方案 1:
不要使用TableRow
作为中间值。换句话说,尽快转换为 POJO。发生这种类型混淆的关键原因是 TableRow
本质上是一个 Map<String, Object>
而 Jackson(或其他编码员)不知道你想要一个 Long
回来。使用 POJO,类型会很清楚。
关闭 TableRow
的另一个好处是获得高效的编码器,例如 AvroCoder
。因为 TableRow
被编码和解码 to/from JSON,编码既冗长又缓慢——洗牌 TableRow
将同时是 CPU- 和 I/O-intensive.我希望你会看到 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
,您可能需要对第二个变体进行额外检查。
在我的 Dataflow 管道中,我将字段 impressions_raw
设置为 com.google.api.services.bigquery.model.TableRow
对象中的 Long
:
在我的管道中,我读回了 TableRow
。但是我得到的不是 Long
,而是 Integer
.
但是,如果我明确将值设置为大于 Integer.MAX_VALUE
的 Long
值,例如 30 亿,那么我会得到一个 Long
!
Dataflow SDK 似乎在幕后进行某种类型检查优化。
那么,如果不进行丑陋的类型检查,应该如何以编程方式处理这个问题? (也许我错过了一些明显的东西)
感谢您的报告。不幸的是,这个问题是使用 TableRow
的基础。我们强烈推荐下面的解决方案 1:在您的管道中尽快从 TableRow
转换。
您存储这些值的 TableRow
对象由 Jackson 在 TableRowJsonCoder
中序列化和反序列化。 Jackson 具有您所描述的行为——也就是说,为此 class:
class MyClass {
Object v;
}
它会将 v = Long.valueOf(<number>)
的实例序列化为 {v: 30}
或 {v: 3000000000}
。然而,在反序列化时,它将使用表示答案所需的位数来确定对象的类型。参见 this SO post。
想到了两种可能的解决方案,强烈推荐解决方案 1:
不要使用
TableRow
作为中间值。换句话说,尽快转换为 POJO。发生这种类型混淆的关键原因是TableRow
本质上是一个Map<String, Object>
而 Jackson(或其他编码员)不知道你想要一个Long
回来。使用 POJO,类型会很清楚。关闭
TableRow
的另一个好处是获得高效的编码器,例如AvroCoder
。因为TableRow
被编码和解码 to/from JSON,编码既冗长又缓慢——洗牌TableRow
将同时是 CPU- 和 I/O-intensive.我希望你会看到 Avro 编码的 POJO 的性能比你传递TableRow
对象要好得多。有关示例,请参阅
LaneInfo
inTrafficMaxLaneFlow
。编写可以处理两者的代码:
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
,您可能需要对第二个变体进行额外检查。