Dataflow在本地返回正确的类型,但在云中执行时则不会

时间:2015-11-26 11:34:05

标签: google-bigquery google-cloud-dataflow

给出BigQuery中的下表:

enter image description here

使用以下5个值:

enter image description here

一个简单的ParDo读取它,并打印出类型:

import com.google.api.services.bigquery.model.TableRow;
import com.google.cloud.dataflow.sdk.Pipeline;
import com.google.cloud.dataflow.sdk.io.BigQueryIO;
import com.google.cloud.dataflow.sdk.options.DataflowPipelineOptions;
import com.google.cloud.dataflow.sdk.options.DataflowPipelineWorkerPoolOptions;
import com.google.cloud.dataflow.sdk.options.PipelineOptionsFactory;
import com.google.cloud.dataflow.sdk.runners.BlockingDataflowPipelineRunner;
import com.google.cloud.dataflow.sdk.transforms.DoFn;
import com.google.cloud.dataflow.sdk.transforms.ParDo;

public class FloatBug {
    public static void main(String[] args) {
        DataflowPipelineOptions options = PipelineOptionsFactory.create().as(DataflowPipelineOptions.class);
        options.setRunner(BlockingDataflowPipelineRunner.class);
        options.setProject("<project_id>");
        options.setWorkerMachineType("n1-standard-1");
        options.setZone("us-central1-a");
        options.setStagingLocation("<gcs_bucket>");
        options.setNumWorkers(1);
        options.setMaxNumWorkers(1);
        options.setAutoscalingAlgorithm(DataflowPipelineWorkerPoolOptions.AutoscalingAlgorithmType.NONE);
        Pipeline pipeline = Pipeline.create(options);

        pipeline.apply(BigQueryIO.Read.from("FLOAT_BUG.float_bug")).apply(ParDo.of(new DoFn<TableRow, TableRow>() {
            @Override
            public void processElement(ProcessContext c) throws Exception {
                Object o = c.element().get("VHH");
                if (o instanceof Double) {
                    System.out.println("Awesome. Got expected Double: " + o);
                } else if (o instanceof Integer) {
                    System.out.println("Bummer. Got an Integer: " + o);
                } else {
                    assert false;
                }
            }
        }));
        pipeline.run();
    }
}

在本地运行会为每个值返回一个Double。这就是我所期望的:

Awesome. Got expected Double: 2.0
Awesome. Got expected Double: 2.245
Awesome. Got expected Double: 1.773
Awesome. Got expected Double: 4.567
Awesome. Got expected Double: 1.342

但是,使用数据流服务在中运行会为值Integer返回2.0

Awesome. Got expected Double: 2.245
Awesome. Got expected Double: 1.342
Awesome. Got expected Double: 1.773
Awesome. Got expected Double: 4.567
Bummer. Got an Integer: 2

它应该返回Double,而不是2.0 {/ p>的Integer

1 个答案:

答案 0 :(得分:2)

观察是真的。从BigQuery读取输入的管道可以输出与BigQuery架构中的基础数据类型不同的类型的数据。如所观察到的,类型也可能因元素而异。

Dataflow Service首先将数据从BigQuery导出到Google Cloud Storage中的JSON编码文件,然后从这些文件中读取数据,这是一个令人遗憾的结果。显然,JSON不保留类型。例如,浮点数2.0将被编码为字符串"2",在Java中将被读取为Integer。使用DirectPipelineRunner执行管道时不会发生这种情况,因为该运行器直接从BigQuery读取。

现在,避免这类问题的最简单方法是通过Java中的Number抽象类。这是像DoubleInteger这样的类的超类。将结果解释为Number然后在其上调用doubleValue()方法应该是安全的。

那说,前进,我希望这种行为能够改变。确切的时间线尚不清楚,但数据流服务的行为应该很快就会与本地执行相匹配。通过Number类的解决方法应该是正确的。