文章目录
- 1. Flink读取Kafka数据
- 2. 读取不同数据类型的kafka数据
Flink有封装好的读写kafka数据的connector可以直接使用,但不同的数据格式该使用什么方法获取?自己想要的自定义数据格式,如byte[]等原生没有,又该如何实现?下面进行详细介绍。
1. Flink读取Kafka数据
引入的pom依赖(根据具体kafka的版本选择,笔者使用的kafka是0.9版本)
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-connector-kafka-0.9_2.11</artifactId>
<version>1.7.1</version>
</dependency>
下面以常用的读取String格式数据为例进行说明,具体使用方法如下:
import org.apache.flink.api.common.serialization.SimpleStringSchema;
import org.apache.flink.streaming.connectors.kafka.FlinkKafkaConsumer09;
import org.apache.kafka.clients.consumer.ConsumerConfig;
import java.util.Properties;
public class KafkaUtils {
public static FlinkKafkaConsumer09<String> getStringConsumer(String topic, String broker, String groupid) {
Properties properties = new Properties();
properties.setProperty(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, broker);
properties.setProperty(ConsumerConfig.GROUP_ID_CONFIG, groupid);
FlinkKafkaConsumer09<String> myConsumer = new FlinkKafkaConsumer09<String>(topic, new SimpleStringSchema(),
properties);
// 从上次消费offset处读取
myConsumer.setStartFromGroupOffsets();
return myConsumer;
}
从上述可知,消费kafka除了需要topic, broker, groupid信息, SimpleStringSchema才是控制读取到的数据类型为String的。进入FlinkKafkaConsumer09构造方法,可以看到DeserializationSchema和KeyedDeserializationSchema的作用是将获取到的byte[]类型数据反序列化为flink的类对象,SimpleStringSchema即是实现DeserializationSchema接口的一个子类。那么我们就可以去自己实现这两个接口得到自定义的数据类型。
2. 读取不同数据类型的kafka数据
从小节1可知,我们可以通过实现DeserializationSchema或KeyedDeserializationSchema来得到自己不同格式类型的数据。
图1 DeserializationSchema已实现类
新建类实现DeserializationSchema的deserialize(byte[] message)
方法即可生成新的获取其它格式数据的schema类。如SimpleStringSchema类的实现方式如下:
我们如果不想让数据反序列化,想要直接读取byte[]格式的数据,就在deserialize方法中,把message直接返回即可。
图2 KeyedDeserializationSchema已实现类
KeyedDeserializationSchema接口相比DeserializationSchema包含更多信息,DeserializationSchema仅能处理kafka消息的消息体message,而KeyedDeserializationSchema还可以拿到每条message的messageKey、topic、partition和offset。例如JSONKeyValueDeserializationSchema类就是将这些信息封装成了JSON对象,使得获取到的DataStream每条数据格式都是一个JSON对象。源码中实现如下:
得到DataStream<ObjectNode>,可以通过访问ObjectNode对象去获取每条数据的具体信息。
当然也可以自己去实现这两个方法,获得自己任意想要的数据格式。例如,笔者想要获取Tuple2<String, byte[]>格式的kafka数据,f0位置为topic, partition, offset组成的UUID去标识每条消息的唯一性,f1位置为原message,那么如下实现即可。
import org.apache.flink.api.common.typeinfo.TypeInformation;
import org.apache.flink.api.java.tuple.Tuple2;
import org.apache.flink.streaming.util.serialization.KeyedDeserializationSchema;
import java.util.UUID;
import static org.apache.flink.api.java.typeutils.TypeExtractor.getForClass;
public class ByteWithMetaDeserialzationSchema implements KeyedDeserializationSchema<Tuple2<String, byte[]>> {
Tuple2<String, byte[]> tuple = null;
@Override
public Tuple2<String, byte[]> deserialize(byte[] messageKey, byte[] message,
String topic, int partition, long offset) {
tuple = new Tuple2<>();
String messageId = new StringBuilder()
.append(topic).append("_")
.append(partition).append("_")
.append(offset).toString();
tuple.f0 = UUID.nameUUIDFromBytes(messageId.getBytes()).toString();
tuple.f1 = message;
return tuple;
}
@Override
public boolean isEndOfStream(Tuple2<String, byte[]> nextElement) {
return false;
}
@Override
public TypeInformation<Tuple2<String, byte[]>> getProducedType() {
Class clazz = Tuple2.class;
return getForClass(clazz);
}
}