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連接信息的)