Apache flink flink数据流键控API

Apache flink flink数据流键控API,apache-flink,Apache Flink,我是Flink的新手,以下是流媒体模式的字数: //x is the stream of (word, 1) val x: DataStream[(String, Int)] = text .flatMap(_.toLowerCase.split("\\W+")) .map((_, 1)) //keyBy on the word field, what does the Tuple here mean in y val y: KeyedStream[(String, Int),

我是Flink的新手,以下是流媒体模式的字数:

//x is the stream of (word, 1)
val x: DataStream[(String, Int)] = text
  .flatMap(_.toLowerCase.split("\\W+")) 
  .map((_, 1))

//keyBy on the word field, what does the Tuple here mean in y   
val y: KeyedStream[(String, Int), Tuple] = x.keyBy(0)  

val z: DataStream[(String, Int)] = y.sum(1)

z.print
假设
x
(“a”,1),(“b”,1),(“c”,1),(“a”,1),(“c”,1),(“c”,1)的流
y
看起来像什么(我不明白这里的
Tuple
是什么意思),那么
z
看起来像什么?

当您指定keyBy(0)时,您是通过流中元组的第一个元素为流设置键,或者换句话说,您是通过单词字符串为流设置键。但是,编译器无法确定键是字符串,因此此版本的keyBy始终将键视为包含某个对象(即实际键)的元组

如果您将keyBy重写为
keyBy(u.\u 1)
,那么编译器将能够推断出密钥类型,并且y将是
KeyedStream[(String,Int),String]
,这应该感觉更好

对流进行键控所完成的是对流进行分区,类似于SQL中的groupBy将表拆分为不相交、不重叠的组的方式。因此,在这种情况下,流(“a”,1),(“b”,1),(“c”,1),(“a”,1),(“c”,1),(“c”,1)在逻辑上分为三组:

("a",1), ("a",1)
("b",1)
("c",1), ("c",1), ("c",1)
然后,计算每个元组的总和(1),通过将每个组中所有元组中的第二个字段相加,可以减少(在map/reduce意义上)每个元组。所以,(“a”,1),(“a”,1)变成(“a”,2),依此类推

与其使用
z=y.sum(1)
,不如更全面地理解以下内容:

val z: DataStream[(String, Int)] = y.reduce(new ReduceFunction[(String, Int)] {
  override def reduce(t1: (String, Int), t2: (String, Int)): (String, Int) =
    (t1._1, t1._2 + t2._2)
})
如果运行代码,您可以精确地看到z的样子。如果您给它足够的资源,它可以在三个独立的线程中运行(因为有三个不同的键)。我刚才得到了这些结果:

3> (a,1)
2> (c,1)
1> (b,1)
2> (c,2)
2> (c,3)
3> (a,2)

其中1>、2>和3>表示哪个线程负责该行的输出。

感谢@David提供的有用答案。现在我明白多了。当调用y.print时,它打印(a,1),(a,1)…(c,1),(c,1),相同的单词将由相同的线程打印,但是y.sum(1)做什么呢?它如何涉及基于同一个单词的sum 1?我无法想象它是如何产生数据流的,@Tom,我已经扩展了我的答案。我希望这能有所帮助。谢谢@david anderson,这对我来说真是个完美的答案!