使用Avrocoder进行自定义类型和泛型

时间:2015-10-14 23:17:08

标签: google-cloud-platform avro google-cloud-dataflow

我正在尝试使用AvroCoder序列化自定义类型,该类型在我的管道中的PCollections中传递。自定义类型有一个通用字段(当前是一个字符串)当我运行管道时,我得到如下的AvroTypeException可能是由于泛型字段。为这个对象构建和传递AvroSchema是解决这个问题的唯一方法吗?

Exception in thread "main" org.apache.avro.AvroTypeException: Unknown type: T
 at org.apache.avro.specific.SpecificData.createSchema(SpecificData.java:255)
 at org.apache.avro.reflect.ReflectData.createSchema(ReflectData.java:514)
 at org.apache.avro.reflect.ReflectData.createFieldSchema(ReflectData.java:593)
 at org.apache.avro.reflect.ReflectData.createSchema(ReflectData.java:472)
 at org.apache.avro.specific.SpecificData.getSchema(SpecificData.java:189)
 at com.google.cloud.dataflow.sdk.coders.AvroCoder.of(AvroCoder.java:116)

我还附上了我的注册码以供参考。

pipelineCoderRegistry.registerCoder(GenericTypeClass.class, new CoderFactory() {
    @Override
    public Coder<?> create(List<? extends Coder<?>> componentCoders) {
        return AvroCoder.of(GenericTypeClass.class);
    }

    @Override
    public List<Object> getInstanceComponents(Object value) {
        return Collections.singletonList(((GenericTypeClass<Object>) value).key);
    }
});

1 个答案:

答案 0 :(得分:7)

就设置CoderFactory而言,您已做好一切准备,但ReflectData用于自动生成架构的Avro AvroCoder机制不适用于泛型类型,因为这篇文章。这被视为问题AVRO-1571。另请参阅this StackOverflow question

为了允许对GenericTypeClass<T>的某些特定值进行T编码,您必须提供一些显式的架构信息。有两种方法可以继续:

第一种方法是在T中为GenericTypeClass<T>类型的字段提供明确的架构,如下所示:

class GenericTypeClass<T> {
  // Avro requires a no-args constructor
  public GenericTypeClass() {}

  @AvroSchema("[\"string\", \"int\", ...]")
  private T genericField;
}

缺点是它仅限于有限的静态联合模式,并且需要手动内联JSON模式以获得更复杂的T值。

第二种方法是在AvroCoder中构建CoderFactory时提供明确的架构,并将此架构提供给AvroCoder.of(Class, Schema)

pipelineCoderRegistry.registerCoder(GenericTypeClass.class, new CoderFactory() {
  @Override
  public Coder<?> create(List<? extends Coder<?>> componentCoders) {
      return AvroCoder.of(
          GenericTypeClass.class
          schemaFromCoder(componentCoders.get(0)));
  }

  ...
});

这主要围绕将Coder<T>转换为T的架构。这对于基本类型应该很容易,并且对ReflectData支持的POJO可以管理。它还为更加困难的案件的临时支持提供了一个钩子。