业务场景
我的实时订单流想要关联另一个流的维度数据,我们该如何设计。
•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”,“机器学习”,“前端”,“中台”,“架构”获取海量学习资料~~~
你也「在看」吗