Apache flink Flink-KeyedProcessFunction排序

Apache flink Flink-KeyedProcessFunction排序,apache-flink,flink-streaming,Apache Flink,Flink Streaming,我是Flink的新手,我试图理解Flink是如何在其KeyedProcessFunction的并行抽象中命令调用processElement()。考虑这个产生部分和的流的例子: package sample import org.apache.flink.api.common.state.{ValueState, ValueStateDescriptor} import org.apache.flink.streaming.api.functions.KeyedProcessFunction

我是Flink的新手,我试图理解Flink是如何在其
KeyedProcessFunction
的并行抽象中命令调用
processElement()
。考虑这个产生部分和的流的例子:

package sample

import org.apache.flink.api.common.state.{ValueState, ValueStateDescriptor}
import org.apache.flink.streaming.api.functions.KeyedProcessFunction
import org.apache.flink.streaming.api.scala.{DataStream, StreamExecutionEnvironment, createTypeInformation}
import org.apache.flink.util.Collector

object Playground {
  case class Record(groupId: String, score: Int) {}

  def main(args: Array[String]): Unit = {
    // 1. Create the environment
    val env: StreamExecutionEnvironment = StreamExecutionEnvironment.createLocalEnvironment()
    env.setParallelism(10)

    // 2. Source
    val record1 = Record("groupX", 1)
    val record2 = Record("groupX", 2)
    val record3 = Record("groupX", 3)
    val records: DataStream[Record] = env.fromElements(record1, record2, record3, record1, record2, record3)

    // 3. Application Logic
    val partialSums: DataStream[Int] = records
      .keyBy(record => record.groupId)
      .process(new KeyedProcessFunction[String, Record, Int] {
        // Store partial sum of score for Records seen
        lazy val partialSum: ValueState[Int] = getRuntimeContext.getState(
          new ValueStateDescriptor[Int]("partialSum", classOf[Int]))

        // Ingest new record
        override
        def processElement(value: Record,
                           ctx: KeyedProcessFunction[String, Record, Int]#Context,
                           out: Collector[Int]): Unit =
        {
          val currentSum: Int = partialSum.value()
          partialSum.update(currentSum + value.score)
          out.collect(partialSum.value())
        }
      })

    // 4. Sink
    partialSums.print()

    // 5. Build JobGraph and execute
    env.execute("sample-job")
  }
}
我希望它的输出是流:
1、3、6、7、9、12
。事实上,就在这里


可以安全地假设这种情况始终存在,特别是在从并行度较高的源读取时?

在您的示例中,每个键内的顺序都是有保证的。由于只有一个键,您将始终获得
1、3、6、7、9、12

当您从并行度大于1的源读取时,各种源实例将相互竞争。当来自两个或多个源的流被连接(例如,通过keyBy、union、rebalance等)时,结果是不确定的(但来自每个源的事件将保持其相对顺序)

例如,如果你有

stream X: 1, 2, 3, 4
stream Y: a, b, c, d
然后把这两条溪流汇集在一起,你可能会


1、2、3、4、a、b、c、d
,或
a、b、1、2、3、c、4、d
,等等。

谢谢David!作为跟进,如果我知道“groupX”中的所有数据都是由制作人按顺序插入AWS Kinesis stream/Kafka主题的一个碎片中(例如,使用分区键),并且知道Flink连接器按顺序从碎片中拉出,那么我可以保证groupX的数据将按顺序通过我的Flink数据流DAG?在这种情况下,来自groupX的所有数据似乎都来自一个子任务,并流向一个子任务,因此保留了顺序。是的,这是正确的。