混合 Integer 和 Long 类型的数据流

Dataflow mixing Integer & Long types

在我的 Dataflow 管道中,我将字段 impressions_raw 设置为 com.google.api.services.bigquery.model.TableRow 对象中的 Long

在我的管道中,我读回了 TableRow。但是我得到的不是 Long,而是 Integer.

但是,如果我明确将值设置为大于 Integer.MAX_VALUELong 值,例如 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:

  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

  2. 编写可以处理两者的代码:

    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,您可能需要对第二个变体进行额外检查。