在Dataflow Generic中进行转换

时间:2015-09-15 17:13:23

标签: java generics google-cloud-platform google-cloud-dataflow

这与另一个SO问题[这里](Setting Custom Coders & Handling Parameterized types)有关。在解决方法之后,帮助我在变换中使用自定义类型。但由于我的自定义类型是通用的,我希望甚至使变换类通用,然后可以使用相同的类型参数化自定义类型。但是当我尝试这样做时,我遇到了无法为类型变量T提供编码器,因为实际类型因擦除而未知。工作中建议注册一个可以返回类型参数的编码器,但由于类型参数本身是未知的,我想这个异常被抛出,我不知道如何解决这个问题。

static class Processor<T> 
  extends PTransform<PCollection<String>, 
                     PCollection<KV<String, Set<CustomType<T>>>>> { 

  private static final long serialVersionUID = 0; 

  @Override public PCollection<KV<String, Set<CustomType<T>>>>  
  apply(PCollection<String> items) {
    PCollection<KV<String, Set<CustomType<T>>>> partitionedItems = items     
        .apply(ParDo.of(new ParDoFn())); 
    PCollection<KV<String, Set<CustomType<T>>>> combinedItems = partitionedItems
        .apply(Combine.<String, Set<CustomType<T>>>perKey(new Merger()));
  }
} 

1 个答案:

答案 0 :(得分:4)

这看起来也是由Github Issue #57引起的,应该与该问题一起解决。

与此同时,Dataflow实际上包含可以立即解决问题的高级功能。从您的代码段看来,整个系统可能看起来像这样:

class CustomType<T extends Serializable> { ... }

class Processor<T extends Serializable>
    extends PTransform<PCollection<String>,
                       PCollection<KV<String, Set<CustomType<T>>>>> {

    class ParDoFn extends DoFn<String, KV<String, Set<CustomType<T>>>> { … }

    class Merger extends BinaryCombineFn<Set<CustomType<T>>> { … }

    @Override
    public PCollection<KV<String, Set<CustomType<T>>>>
    apply(PCollection<String> items) {

      PCollection<KV<String, Set<CustomType<T>>>> partitionedItems =
          items.apply(ParDo.of(new ParDoFn()));

      PCollection<KV<String, Set<CustomType<T>>>> combinedItems =
          partitionedItems.apply(
              Combine.<String, Set<CustomType<T>>, Set<CustomType<T>>>perKey(
                  new Merger()));

      return combinedItems;
    }
}

…

PCollection<String> input = ...
input.apply(new Processor<String>());

数据流使用getOutputTypeDescriptor

返回的DoFn获取每个TypeDescriptor的输出类型

因为ParDoFnProcessor<T>的内部类,所以输出类型描述符只是Set<CustomType<T>>,即使它被实例化为新Processor<String>

要获取类型信息,我们需要ParDoFn静态了解为T提供的类型。这有两个步骤。

<强> 1。创建Processor

的匿名子类
PCollection<String> input = ...
input.apply(new Processor<String>() {});

这确保了对于Processor此实例的所有内部类,类型变量T 静态绑定到类型String。在这种情况下,最好将Processor作为一个抽象类,以便消费者将其子类化。

2.Override getOutputTypeDescriptor ParDoFn以解析外部类Processor的类型。

class Processor<T extends Serializable> extends ... {
  class ParDoFn extends DoFn<String, KV<String, Set<CustomType<T>>>> {
    @Override
    protected TypeDescriptor<KV<String, Set<CustomType<T>>>>
    getOutputTypeDescriptor() {
      return new TypeDescriptor<KV<String, Set<CustomType<T>>>>(
        Processor.this.getClass()) {};
    }
 }

从一开始,代码的完整工作版本如下。请再次注意,解析Github Issue #57时无需执行此操作。

class CustomType<T extends Serializable> { ... }

abstract class Processor<T extends Serializable>
    extends PTransform<PCollection<String>,
                       PCollection<KV<String, Set<CustomType<T>>>>> {

  class ParDoFn extends DoFn<String, KV<String, Set<CustomType<T>>>> {
    ...

    @Override
    protected TypeDescriptor<KV<String, Set<CustomType<T>>>> 
    getOutputTypeDescriptor() {
      return new TypeDescriptor<KV<String, Set<CustomType<T>>>>(
          Processor.this.getClass()) {};
    }
  }

  class Merger extends BinaryCombineFn<Set<CustomType<T>>> { ... }

    @Override
    public PCollection<KV<String, Set<CustomType<T>>>> apply(PCollection<String> items) {

    PCollection<KV<String, Set<CustomType<T>>>> partitionedItems =
        items.apply(ParDo.of(new ParDoFn()));

    PCollection<KV<String, Set<CustomType<T>>>> combinedItems =
        partitionedItems.apply(
          Combine.<String, Set<CustomType<T>>, Set<CustomType<T>>>perKey(
              new Merger()));

    return combinedItems;
  }
}

PCollection<String> input = …;
input.apply(new Processor<String>() {});

这不是唯一的解决方案 - 您也可以覆盖Processor.getDefaultOutputCoder或在中间partitionedItems集合上明确调用setCoder - 但它似乎是最常用的