数据流混合Integer和Long类型

Gra*_*ley 5 google-cloud-platform google-cloud-dataflow

在我的数据流的管道,我设置字段impressions_raw作为Long一个com.google.api.services.bigquery.model.TableRow对象:

在此输入图像描述

在我的管道中,我读了TableRow回来.但是,而不是一个Long,我回来了Integer.

在此输入图像描述

但是,如果我明确地将值设置为Long大于Integer.MAX_VALUE,例如30亿的值,那么我回来了Long!

在此输入图像描述 在此输入图像描述

似乎Dataflow SDK正在进行某种类型的检查优化.

因此,如果不进行丑陋的类型检查,应该如何以编程方式处理此问题?(也许我错过了一些明显的事)

Dan*_*rin 4

感谢您的报告。不幸的是,这个问题对于使用TableRow. TableRow我们强烈推荐下面的解决方案 1:在您的管道中尽快转换。

您存储这些值的对象TableRow由 Jackson 在TableRowJsonCoder. 杰克逊的行为正是您所描述的——也就是说,对于这个类:

class MyClass {
    Object v;
}
Run Code Online (Sandbox Code Playgroud)

它将使用v = Long.valueOf(<number>)as{v: 30}或序列化一个实例{v: 3000000000}。然而,在反序列化时,它将使用表示答案所需的位数来确定对象的类型。请参阅此帖子

我想到了两种可能的解决方案,强烈推荐解决方案 1:

  1. 不要用作TableRow中间值。也就是说,尽快转换为POJO。发生这种类型混合的关键原因是TableRow本质上是Map<String, Object>杰克逊(或其他编码员)无法知道你想要一个Long背部。有了 POJO,类型就会很清楚。

    关闭的另一个好处TableRow是获得高效的编码器,例如AvroCoder。因为TableRows 是与 JSON 进行编码和解码的,所以编码既冗长又缓慢——洗牌TableRow将是 CPU 和 I/O 密集型的。我希望您会看到 Avro 编码的 POJO 比传递TableRow对象的性能要好得多。

    有关示例,请参见LaneInfoTrafficMaxLaneFlow

  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"));
    
    Run Code Online (Sandbox Code Playgroud)

    n如果可能的话,您可能需要对第二个变体进行额外的检查null