2015-10-14 21 views
4

我想使用AvroCoder序列化傳遞在我的管道中的PCollections周圍的自定義類型。自定義類型有一個通用的字段(當前是一個字符串)當我運行管道時,可能由於泛型字段,我得到如下所示的AvroTypeException。是否構建並傳遞AvroSchema作爲解決此問題的唯一方法?使用Avrocoder自定義類型與泛型

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); 
    } 
}); 

回答

7

你的權利,只要設立CoderFactory所做的一切,但Avro公司的ReflectDataAvroCoder使用自動生成的架構機制不泛型類型的工作,寫這篇文章的。這被追蹤爲問題AVRO-1571。另見this StackOverflow question

爲了允許對T的某些特定值編碼GenericTypeClass<T>,您必須提供一些明確的模式信息纔是正確的。有兩種方式進行:

第一種方法是你GenericTypeClass<T>內提供T類型的字段明確的架構,就像這樣:

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

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

的缺點是,它被限制在一個有限的,靜態聯合模式,並且需要手動內聯JSON模式以獲得更復雜的值T

第二種方法是在您的CoderFactory中構建AvroCoder時提供顯式模式,並將此模式提供給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,這應該很容易適用於基本類型並且易於管理。它也提供了一個特別支持更困難的案例的鉤子。

+0

謝謝。我覺得第二個選項在我的情況下也更清潔。至於將編碼器轉換爲模式,我應該提供整個對象的模式還是僅提供對象內的泛型類型(在我的情況下是字符串)?我無法弄清楚如何從編碼器執行轉換... – user1089464

+0

在諸如AvroCoder.of(GenericTypeClass.class,schema)的調用中傳遞的模式應該是GenericTypeClass 的完整模式。 –

+0

所以我嘗試使用@AvroSchema(「[\」string \「])在泛型類defn中的參數化類型上,但是現在,當我在數據流中使用它對抗AvroCoder時,我得到這樣的錯誤 'java.lang .RuntimeException:java.lang.NoSuchMethodException:com.package.GenericType。()\ n \ tat org.apache.avro.specific.SpecificData.newInstance(SpecificData.java:316) 引起:java.lang.NoSuchMethodException:com .package.GenericType。()\ n \ tat java.lang.Class.getConstructor0(Class.java:3082)\ n \ tat java.lang.Class.getDeclaredConstructor(Class.java:2178)\ n \ t' – user1089464