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

google-cloud-platform - 数据流混合整数和长整型-LMLPHP

在我的管道中,进一步读回TableRow。但是我取回了Long而不是Integer

google-cloud-platform - 数据流混合整数和长整型-LMLPHP

但是,如果我将值显式设置为大于LongInteger.MAX_VALUE值(例如30亿),那么我将获得Long!

google-cloud-platform - 数据流混合整数和长整型-LMLPHP
google-cloud-platform - 数据流混合整数和长整型-LMLPHP

似乎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/

    10-11 09:22