BQ切换到TIMESTAMP分区表

时间:2019-02-07 16:08:45

标签: google-bigquery google-cloud-dataflow google-cloud-pubsub

我正在尝试将IngestionTime(_PARTITIONTIME)迁移到BQ中的TIMESTAMP分区表。为此,我还需要添加一些必填列。但是,当我翻转开关并将数据流重定向到新的TIMESTAMP分区表时,它中断了。注意事项:

  • 成功插入了大约200万行(可能是一批)。作业继续运行,但此后未插入任何内容。
  • 作业分批运行。
  • 我的项目完全是用Java
  • 当我将其作为流媒体运行时,它似乎可以正常工作。不幸的是,对于我的用例来说这是不切实际的,并且需要批处理。

我已经调查了几天,并试图将过渡过程分解为最小的步骤。似乎导致该错误的步骤是引入了REQUIRED变量(当相同的变量为NULLABLE时,它工作正常)。为了避免任何可能的解析错误,我为所有必需的变量设置了默认值。

目前,我收到以下错误组合,但不确定如何解决其中的任何错误:

第一个错误很少重复出现,但通常以组的形式重复出现:

  

找不到配置文件代理。个人资料将不可用   工人

发生很多且成群结队:

  

无法验证BoundedSource类型的序列化元素是否具有定义良好的equals方法。这可能会在某些PipelineRunner上产生不正确的结果

似乎是其中一个很大的群体:

  

中止操作。 java.lang.RuntimeException:无法从状态读取值

最后,此错误每5分钟出现一次,仅在下面所述的轻微解析错误周围。

  

处理停留在步骤BigQueryIO.Write / BatchLoads / SinglePartitionWriteTables / ParMultiDo(WriteTables)至少20m00,而没有在状态完成时输出或完成

由于我的项目解析的数据量巨大,因此存在一些解析错误,例如意外字符。它们很少见,但不应破坏数据插入。如果是这样,我会遇到更大的问题,因为我收集的数据经常更改,并且只有在看到错误之后才能调整解析器,因此,请参见新的数据格式。此外,这不会导致摄取时间表中断(或其他时间戳分区表中断)。话虽如此,这是一个解析错误的示例:

  

错误:意外字符(','(代码44)):期望双引号开头字段名称

编辑: 一些相关的示例代码:

public PipelineResult streamData() {
        try {
            GenericSection generic = new GenericSection(options.getBQProject(), options.getBQDataset(), options.getBQTable());
            Pipeline pipeline = Pipeline.create(options);

            pipeline.apply("Read PubSub Events", PubsubIO.readMessagesWithAttributes().fromSubscription(options.getInputSubscription()))
                                              .apply(options.getWindowDuration() + " Windowing",  generic.getWindowDuration(options.getWindowDuration()))
                                              .apply(generic.getPubsubToString())
                                              .apply(ParDo.of(new CrowdStrikeFunctions.RowBuilder()))
                                              .apply(new BigQueryBuilder().setBQDest(generic.getBQDest())
                                                                          .setStreaming(options.getStreamingUpload())
                                                                          .setTriggeringFrequency(options.getTriggeringFrequency())

                                                                          .build());

            return pipeline.run();
        } 
        catch (Exception e) {
            LOG.error(e.getMessage(), e);
            return null;
        }

写信给BQ。我确实尝试直接在此处设置partitoning字段,但它似乎没有任何影响:

BigQueryIO.writeTableRows()
                .to(BQDest)
                .withMethod(Method.FILE_LOADS)
                .withNumFileShards(1000)
                .withTriggeringFrequency(this.triggeringFrequency)
                .withTimePartitioning(new TimePartitioning().setType("DAY"))
                .withWriteDisposition(BigQueryIO.Write.WriteDisposition.WRITE_APPEND)
                .withCreateDisposition(BigQueryIO.Write.CreateDisposition.CREATE_NEVER);
    }

1 个答案:

答案 0 :(得分:0)

经过大量挖掘,我发现了错误。我有一个解析逻辑(一个try / catch),在发生解析错误的情况下不返回任何内容(本质上是一个空行)。这将破坏BigQuery,因为我的架构有多个REQUIRED行。

由于我的作业是成批运行的,因此即使是空行也将导致整个批处理作业失败并且不插入任何内容。这也解释了为什么插入流就可以了。令我感到惊讶的是,BigQuery没有抛出错误,声称我正在尝试将null插入必填字段。

在得出这个结论时,我还意识到,与在模式中相反,在代码中设置分区字段也是必要的。可以使用

.setField(partitionField)