我是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
会是什么样子?
答案 0 :(得分:2)
当您指定keyBy(0)时,您将通过流中元组的第一个元素来对流进行键控,换句话说,您将通过单词字符串来对流进行键控。但是,编译器无法确定键是字符串,因此此版本的keyBy始终将键视为包含某些对象(即实际键)的元组。
如果将keyBy重写为keyBy(_._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)
然后,通过将每个组中所有元组中的第二个字段相加,对每一个进行计算sum(1)会减少(在映射/减少意义上)每一个。因此,(“ 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>指示哪个线程负责该行输出。