1、使用flink提供的RedisSink
(1)添加maven依赖
<dependency>
<groupId>org.apache.bahir</groupId>
<artifactId>flink-connector-redis_2.11</artifactId>
<version>1.1-SNAPSHOT</version>
</dependency>
(2)实现一个redisMapper
创建一个类,继承 RedisMapper<T>接口,如下代码示例所示,
public static class RedisExampleMapper implements RedisMapper<Tuple2<String, String>>{
@Override
public RedisCommandDescription getCommandDescription() {
return new RedisCommandDescription(RedisCommand.HSET, "HASH_NAME");
}
@Override
public String getKeyFromData(Tuple2<String, String> data) {
return data.f0;
}
@Override
public String getValueFromData(Tuple2<String, String> data) {
return data.f1;
}
}
注意了,如果使用Hash类型的话,这里的Hash key就得写死,也就是说这个key不能动态的从接收到的数据中获取(太别扭了,不知道还有没有其他动态设置的方式,有则劳烦告知)
下面分别讲一下这里实现的这三个方法
- RedisCommandDescription()方法用于指定对接收来的数据进行什么操作,示例中指定为HSET操作,也可以指定为SET操作等等,另外指定HSET操作时需要跟上key参数。
- getKeyFromData()方法用于指定接收到的数据中哪部分作为key,示例中,是将数据源中元组数据的第一个值作为key
- getValueFromData()方法用于指定接收到的数据中哪部分作为value,示例中,是将数据源中元组数据的第二个值作为value
(3)通过addSink()方法将实现的RedisSink添加到流上
1、注意先创建好redis连接配置对象,因为创建redisSink时会用到
FlinkJedisPoolConfig conf = new FlinkJedisPoolConfig.Builder().setHost("127.0.0.1").build();
2、添加到流中
DataStream<String> stream = ...;
stream.addSink(new RedisSink<Tuple2<String, String>>(conf, new RedisExampleMapper());
2、自定义Sink
(1)创建一个类,继承RichSinkFunction,这个类就是自定义实现的sink
public class RedisSinkCustom extends RichSinkFunction<avro.ScadaData> {
Configuration parameters;
Jedis jedis = null;
byte[] valueKey = "value".getBytes();
byte[] qualitykey = "quality".getBytes();
byte[] timeKey = "time".getBytes();
public RedisSinkCustom(Configuration parameters){
this.parameters = parameters;
}
@Override
public void open(Configuration parameters) throws Exception {
super.open(this.parameters);
jedis = new Jedis(this.parameters.getString("host","hadoop"),
this.parameters.getInteger("port",6379));
}
@Override
public void invoke(ScadaData value, Context context) {
int dataType = value.getDatatype();
List<avro.SRtValue> datas = value.getData();
String tabName = null;
switch (dataType){
case 1:tabName = "s_analog";break;
case 2:tabName = "s_discrete";break;
}
byte[] hkey = null;
for(avro.SRtValue data:datas){
hkey = new StringBuffer(tabName).append(".").append(data.getId()).toString().getBytes();
jedis.hset(hkey,valueKey,String.valueOf(data.getV()).getBytes());
jedis.hset(hkey,qualitykey,String.valueOf(data.getQ()).getBytes());
jedis.hset(hkey,timeKey,String.valueOf(data.getTime()).getBytes());
}
}
@Override
public void close() throws Exception {
super.close();
jedis.close();
}
继承RichSinkFunction类后,主要重写三个方法 ,分别为:open(),invok(),close()
- open()方法在创建sink时候只调用一次,所以这里可以用于初始化一些资源配置,我这里创建了redis的连接
- invok(Object value, Context context)方法在每次有数据流入时都会调用,所以从源中每过来一个数据都会执行,value参数即为流中的数据元素
- close()方法用于关闭sink时调用,一般用于释放资源
(2)将自定义sink添加到流上
DataStream<ScadaData> stream = ... stream.addSink(new RedisSinkCustom(conf));
(我这里给sink传入的conf参数是我自定义的用来配置redis连接信息的)