Flink寫入Redis的兩種方式

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

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章