業務場景
我的實時訂單流想要關聯另一個流的維度數據,我們該如何設計。
•A流:訂單流,從binlog中獲取下單數據,缺點是,表內維度數據缺少經緯度信息(舉例)。•B流:用戶流量信息,保存用戶的經緯度信息(舉例)
以上場景,是我們在實時數據倉庫開發中,會經常遇到實時關聯維度數據的情況,我們該如何優雅的開發?
通過唯一key做實時流關聯,然後通過union把兩個流做合併,通過flink的state做維度補全。
注意事項
•state保存多久,類型設計,上游異常如何回溯歷史數據?•什麼條件下滿足數據輸出?,如何解決數據先到和後到問題?•爲什麼用state做,而不是把維度數據落到redis內存kv中?優點是什麼?缺點是什麼?•這種設計適合的業務場景是什麼?搞清楚。注意⚠️咱們設計的輸出觸發條件是:“當設備id補全維度數據後再輸出結果”。
簡化代碼
第一步:兩個流處理完之後,並針對每個流添加tag("order_stream","lat_lon_stream")標籤,方便兩個流進行 union之後去識別哪個是訂單流,其中key是deviceid,value是對應的json
val text =order_stream.union(lat_lon_stream).keyBy(0).process(new MyKeyedProcessFunction())
第二步:在MyKeyedProcessFunction實現自己的業務邏輯
class MyKeyedProcessFunction extends KeyedProcessFunction[Tuple, (String, JSONObject), JSONObject]{
//我設計的state類型是mapstate
private var state: MapState[String,String] = _
private var sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
override def open(parameters: Configuration): Unit ={
super.open(parameters)
//我設置的保存時間是1天,大家可以根據業務場景自己設定。
val config = StateTtlConfig.newBuilder(org.apache.flink.api.common.time.Time.days(1))
.setStateVisibility(StateTtlConfig.StateVisibility.NeverReturnExpired)
.setUpdateType(StateTtlConfig.UpdateType.OnCreateAndWrite)
.build()
val mapStateDescriptor =new MapStateDescriptor[String,String]("OrderState", classOf[String], classOf[String])
mapStateDescriptor.enableTimeToLive(config)
state = getRuntimeContext.getMapState(mapStateDescriptor)
}
override def processElement(message: (String, JSONObject),
ctx: KeyedProcessFunction[Tuple, (String, JSONObject), JSONObject]#Context,
out: Collector[JSONObject]) = {
if(message._2.get("tag").toString =="lat_lon_stream"){
//標識我實時經緯度接收的日期(我設計的比較簡單,你們可以細化到小時)
state.put("dau",message._2.get("dt").toString)
state.put("lat_lon",message._2.get("lat_lon").toString)
//如何日期相同,就輸出
if(message._2.get("dt").toString ==state.get("order")){
val jsonObject = JSON.parseObject(state.get("orderInfo"))
jsonObject.put("lat_lon",message._2.get("lat_lon").toString)
out.collect(jsonObject)
}
}else{
//如果tag不是經緯度,那就說明是訂單流,判斷訂單流的日期,和flink中state
//存儲的經緯度日期是否相同,如果相同,說明經緯度流已經到達了
//滿足輸出條件了。(我設計的比較簡單,你們可以細化到小時)
if (state.get("lat_lon") == message._2.get("dt").toString){
val jsonObject = message._2
jsonObject.put("lat_lon",state.get("lat_lon"))
out.collect(jsonObject)
}else{
//標識我實時訂單接收的日期(我設計的比較簡單,你們可以細化到小時)
state.put("order",message._2.get("dt").toString)
state.put("orderInfo",message._2.toString)
}
}
}
}
關注小晨說數據,獲取更多大廠技術乾貨分享
回覆“spark”,“flink”,“機器學習”,“前端”,“中臺”,“架構”獲取海量學習資料~~~
你也「在看」嗎