flink run -s hdfs://zhumei00:9000/flink/savepoints/savepoint-2084e7-591930867f28/_metadata flink-demo-stateful.jar
package org.example.join
import org.apache.flink.api.common.state.ValueStateDescriptor
import org.apache.flink.api.scala.typeutils.Types
import org.apache.flink.streaming.api.TimeCharacteristic
import org.apache.flink.streaming.api.functions.co.CoProcessFunction
import org.apache.flink.streaming.api.scala._
import org.apache.flink.util.Collector
object TwoStreamsJoin {
case class OrderEvent(orderId: String,
eventType: String,
eventTime: Long)
case class PayEvent(orderId: String,
eventType: String,
eventTime: Long)
val unmatchedOrders = new OutputTag[String]("unmatched-orders")
val unmatchedPays = new OutputTag[String]("unmatched-pays")
def main(args: Array[String]): Unit = {
val env = StreamExecutionEnvironment.getExecutionEnvironment
env.setParallelism(1)
env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime)
val orders = env
.fromElements(
OrderEvent("order_1", "pay", 2000L),
OrderEvent("order_2", "pay", 5000L),
OrderEvent("order_3", "pay", 6000L)
)
.assignAscendingTimestamps(_.eventTime)
.keyBy(_.orderId)
val pays = env
.fromElements(
PayEvent("order_4", "weixin", 9000L),
PayEvent("order_1", "weixin", 7000L),
PayEvent("order_2", "weixin", 8000L)
)
.assignAscendingTimestamps(_.eventTime)
.keyBy(_.orderId)
val processed = orders
.connect(pays)
.process(new MatchFunction)
processed.print()
processed.getSideOutput(unmatchedOrders).print()
processed.getSideOutput(unmatchedPays).print()
env.execute()
}
class MatchFunction extends CoProcessFunction[OrderEvent, PayEvent, String] {
lazy val orderState = getRuntimeContext.getState(
new ValueStateDescriptor[OrderEvent]("order-state", Types.of[OrderEvent])
)
lazy val payState = getRuntimeContext.getState(
new ValueStateDescriptor[PayEvent]("pay-state", Types.of[PayEvent])
)
override def processElement1(order: OrderEvent, ctx: CoProcessFunction[OrderEvent, PayEvent, String]#Context, out: Collector[String]): Unit = {
val pay = payState.value()
if (pay != null) {
payState.clear()
out.collect("订单ID为 " + order.orderId + " 的两条流对账成功!")
} else {
orderState.update(order)
ctx.timerService().registerEventTimeTimer(order.eventTime + 5000L)
}
}
override def processElement2(pay: PayEvent, ctx: CoProcessFunction[OrderEvent, PayEvent, String]#Context, out: Collector[String]): Unit = {
val order = orderState.value()
if (order != null) {
orderState.clear()
out.collect("订单ID为 " + pay.orderId + " 的两条流对账成功!")
} else {
payState.update(pay)
ctx.timerService().registerEventTimeTimer(pay.eventTime + 5000L)
}
}
override def onTimer(timestamp: Long, ctx: CoProcessFunction[OrderEvent, PayEvent, String]#OnTimerContext, out: Collector[String]): Unit = {
if (orderState.value() != null) {
ctx.output(unmatchedOrders, "订单ID为 " + orderState.value().orderId + " 的两条流没有对账成功!")
orderState.clear()
}
if (payState.value() != null) {
ctx.output(unmatchedPays, "订单ID为 " + payState.value().orderId + " 的两条流没有对账成功!")
payState.clear()
}
}
}
}