实战:flink实时数仓双流join

本文介绍了如何在Flink实时数据仓库中处理实时订单流与用户流量信息流的关联问题。通过唯一key进行实时流关联,利用state进行维度补全,讨论了state的设计考量、数据输出条件及适用场景,并给出了简化代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

业务场景

我的实时订单流想要关联另一个流的维度数据,我们该如何设计。

•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”,“机器学习”,“前端”,“中台”,“架构”获取海量学习资料~~~

你也「在看」吗

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值