主要目标是汇总两个Kafka主题,一个主题是压缩的慢速移动数据,另一个主题是每秒接收的快速移动数据。
我已经能够在诸如KV(长字符串)之类的简单方案中使用以下消息来消费消息:
PCollection<KV<Long,String>> input = p.apply(KafkaIO.<Long,
String>read()
.withKeyDeserializer(LongDeserializer.class)
.withValueDeserializer(StringDeserializer.class)
PCollection<String> output = input.apply(Values.<String>create());
但是,当您需要从AVRO反序列化时,这似乎不是这种方法。我有一个KV(STRING,AVRO)需要消耗。
我尝试从AVRO模式生成Java类,然后将它们包含在“应用”中,例如:
PCollection<MyClass> output = input.apply(Values.<MyClass>create());
但这似乎不是正确的方法。
有没有人可以指出的文档/示例,因此我可以了解如何使用Kafka AVRO和Beam。 任何帮助将非常感激。
我已更新代码:
import io.confluent.kafka.serializers.KafkaAvroDeserializer;
import org.apache.beam.sdk.Pipeline;
import org.apache.beam.sdk.coders.AvroCoder;
import org.apache.beam.sdk.io.kafka.KafkaIO;
import org.apache.beam.sdk.options.PipelineOptions;
import org.apache.beam.sdk.options.PipelineOptionsFactory;
import org.apache.beam.sdk.values.KV;
import org.apache.beam.sdk.values.PCollection;
import org.apache.kafka.common.serialization.LongDeserializer;
public class Main {
public static void main(String[] args) {
PipelineOptions options = PipelineOptionsFactory.create();
Pipeline p = Pipeline.create(options);
PCollection<KV<Long, Myclass>> input = p.apply(KafkaIO.<Long, String>read()
.withKeyDeserializer(LongDeserializer.class)
.withValueDeserializerAndCoder(KafkaAvroDeserializer.class, AvroCoder.of(Myclass.class))
);
p.run();
}
}
#######################################################
import org.apache.beam.sdk.coders.AvroCoder;
import org.apache.beam.sdk.coders.DefaultCoder;
@DefaultCoder(AvroCoder.class)
public class Myclass{
String name;
String age;
Myclass(){}
Myclass(String n, String a) {
this.name= n;
this.age= a;
}
}
但是我现在得到以下错误不兼容类型:java.lang.Class
我必须导入不正确的序列化程序吗?
答案 0 :(得分:1)
您可以按以下方式使用KafkaAvroDeserializer:
PCollection<KV<Long,MyClass>> input = p.apply(KafkaIO.<Long, String>read()
.withKeyDeserializer(LongDeserializer.class)
.withValueDeserializerAndCoder(KafkaAvroDeserializer.class, AvroCoder.of(MyClass.class))
其中 MyClass 是POJO类生成的Avro架构。
确保您的POJO类具有注释AvroCoder,如下例所示:
@DefaultCoder(AvroCoder.class)
public class MyClass{
String name;
String age;
MyClass(){}
MyClass(String n, String a) {
this.name= n;
this.age= a;
}
}
答案 1 :(得分:0)
将KafkaIO.<Long, String>read()
更改为KafkaIO.<Long, Object>read()
。
如果您研究KafkaAvroDeserializer的实现,它将实现Deserializer:
public class KafkaAvroDeserializer extends AbstractKafkaAvroDeserializer implements Deserializer<Object>
答案 2 :(得分:0)
我也遇到过同样的问题。在此邮件归档中找到了解决方案。 http://mail-archives.apache.org/mod_mbox/beam-user/201710.mbox/%3CCAMsy_NiVrT_9_xfxOtK1inHxb=x_yAdBcBN+4aquu_hn0GJ0nA@mail.gmail.com%3E
对于您的情况,您需要定义自己的 KafkaAvroDeserializer ,如下所示。
public class MyClassKafkaAvroDeserializer extends
AbstractKafkaAvroDeserializer implements Deserializer<MyClass> {
@Override
public void configure(Map<String, ?> configs, boolean isKey) {
configure(new KafkaAvroDeserializerConfig(configs));
}
@Override
public MyClass deserialize(String s, byte[] bytes) {
return (MyClass) this.deserialize(bytes);
}
@Override
public void close() {} }
然后将您的 KafkaAvroDeserializer 指定为ValueDeserializer。
p.apply(KafkaIO.<Long, MyClass>read()
.withKeyDeserializer(LongDeserializer.class)
.withValueDeserializer(MyClassKafkaAvroDeserializer.class) );
答案 3 :(得分:0)
Yohei的回答很好,但是我也发现这行得通
import io.confluent.kafka.streams.serdes.avro.SpecificAvroDeserializer;
...
public static class CustomKafkaAvroDeserializer extends SpecificAvroDeserializer<MyCustomClass> {}
...
.withValueDeserializerAndCoder(CustomKafkaAvroDeserializer.class, AvroCoder.of(MyCustomClass.class))
...
其中MyCustomClass
是使用Avro工具生成的代码。
答案 4 :(得分:0)
我今天有一个类似的问题,遇到了以下示例,为我解决了这个问题。
我缺少的东西是(Class)KafkaAvroDeserializer
KafkaIO.<String, MyClass>read()
.withBootstrapServers("kafka:9092")
.withTopic("dbserver1.inventory.customers")
.withKeyDeserializer(StringDeserializer.class)
.withValueDeserializerAndCoder((Class)KafkaAvroDeserializer.class, AvroCoder.of(MyClass.class))