在Google Dataflow中作为DataflowPipelineRunner运行时访问资源文件

时间:2016-09-22 21:30:05

标签: java google-cloud-dataflow

在我的项目中,我正在尝试向管道中处理的数据添加一些元数据。元数据位于src-folder旁边名为resources的子文件夹中的DBF文件中。

src-folder包含main-class,我有几个包(IO,processing,aggregation,utils)。

我在我的主类中读取并处理带有元数据的文件,其中定义了管道。我用来访问该文件的代码如下:

File temp1 = new File("resources/xxx.dbf");

我使用以下方法检查文件是否已找到:

LOG.info(temp1.exists())

运行良好。

我使用PubSubIO读取了作为字符串的消息。我使用此文件的内容来填充包含键和值的Map。

Map<String, ArrayList<Double>> sensorToCoordinates = coordinateData.getSensorLocations();

然后我在名为&#39; SensorValues&#39;的自定义类中设置一个静态变量。我做了:

SensorValue.setKeyToCoordinates(sensorToCoordinates);

当将来自Strings的传入消息解析为使用ParDo函数(从PCollection到PCollection)创建的SensorValue类时,映射将用于SensorValue类的构造函数中。

使用DirectPipelineRunner运行此代码非常有效。但是,当我使用DataflowPipelineRunner,并尝试访问SensorValue构造函数中的映射时,我遇到了NullPointerException。

现在我想知道为什么在使用DataflowPipelineRunner时我的setter工作不正常(我猜测它与在几个worker之间分配的执行有关)以及使用任何静态资源的最佳做法是什么用文件来丰富你的管道?

1 个答案:

答案 0 :(得分:2)

问题是因为ParDo的执行是分配给多个工作人员的。他们没有本地文件,他们可能没有地图的内容。

这里有几个选项:

  1. 将文件放入GCS,让管道读取文件内容(使用TextIO或类似内容),并将其作为side-input用于以后的处理。

    < / LI>
  2. 将该文件包含在管道的资源中,并在需要它的startBundle的{​​{1}}中加载该文件(将来会有更多的方法来实现这一点)每一包)。

  3. 您可以将地图的内容序列化为DoFn的参数,方法是将其作为传递给该类构造函数的非静态字段放入。

  4. 选项1更好,因为此文件的大小增加(因为它可以支持将其拆分为多块并进行查找),而选项2可能减少检索文件的网络流量。选项3仅在文件非常小的情况下才有效,因为它会显着增加序列化DoFn的大小,这可能导致作业变大以提交到Dataflow服务。