Scala 还原键+映射+顺序解释

Scala 还原键+映射+顺序解释,scala,apache-spark,spark-streaming,scala-collections,Scala,Apache Spark,Spark Streaming,Scala Collections,我试图弄清楚reduceByKey是如何工作的,但这个案例让我困惑,我一点也不理解 代码是: stream.foreachRDD((rdd: RDD[Record]) => { // convert string to PoJo and generate rows as tuple group val pairs = rdd .map(row => (row.timestamp(), jsonDecode(row.value())))

我试图弄清楚reduceByKey是如何工作的,但这个案例让我困惑,我一点也不理解

代码是:

 stream.foreachRDD((rdd: RDD[Record]) => {
      // convert string to PoJo and generate rows as tuple group
    val pairs = rdd
            .map(row => (row.timestamp(), jsonDecode(row.value())))
            .map(row => (row._2.getType.name(), (1, row._2.getValue, row._1)))
    val flatten = pairs
                .reduceByKey((x, y) => (x._1 + y._1, x._2 + y._2, (y._3 + x._3) / 2))
                .map(f => Row.fromSeq(Seq(f._1, f._2._2 / f._2._1, new Timestamp(f._2._3))))
想象一下数据收入: [大洋洲,500],[澳大利亚,450]等

在flatte变量中,我试图按市场类型或JSON中的第一种类型聚合数据。这里是生成元组:*第一个是计数器值,这个值是1, *第二个是从卡夫卡那里得到的利率, *三是活动时间。例如2017-05-12 16:00:00 * *在地图上, *方法f._1是市场名称, *我们将总费率除以项目总数f._2._2/f._2._1 *如您所见,f._2._3是平均事件时间


有人能帮我解释一下f._2._3是什么意思吗?我的意思是我知道它的温度变量,但里面有什么或可能有什么,总速率如何除以f._2._2/f._2._1,到底除以什么?谢谢:

在RDD对中为每一行定义以下元素:

注意,这是一个Tuple2,其第二个元素是Tuple3。元组是特例类,其从1开始的第n个元素名为_n。例如,要访问元素f的速率,必须执行Tuple3的第二个元素f._2._2,这是Tuple2的第二个元素

由于元素具有特殊含义,您可能需要考虑定义一个case类MyRooCurr:int、Rist:int、Time:TimeType,以便在编写F.E.2.2.3这样的代码时更清楚地了解代码所做的事情,顺便说一下,事件类型的类型对我来说并不清楚,因为您只将它表示为字符串,但你要对它进行数值运算

现在让我们来看看您的代码真正想要做什么:

reduce函数使用两个Tuple3或MyRow,如果您更改代码并在此处输出另一个,则reduce函数对计数器、速率求和,并在eventTime上对两个值进行平均

reduceByKey应用此缩减函数,只要它找到具有相同键的两个元素:由于缩减函数的输出类型与输入类型相同,因此只要RDD上有其他具有相同键的值,就可以对其应用此缩减函数

举个简单的例子,如果你有

(key1, (1, 200, 2017/04/04 12:00:00))
(key1, (1, 300, 2017/04/04 12:00:00))
(key1, (1, 500, 2017/04/04 12:00:00))
(key2, (1, 500, 2017/04/04 12:00:00))
然后,reduceByKey将输出

(key1, (3, 1000, 2017/04/04 12:00:00))
(key2, (1, 500, 2017/04/04 12:00:00))
然后,您的最后一张地图将通过计算总费率来处理此问题:

(key1, (333, 2017/04/04 12:00:00))
(key2, (500, 2017/04/04 12:00:00))
你可能已经注意到,在所有的例子中,我总是使用相同的时间。这是因为此字段上的缩减函数将给出意外的结果,因为它不是关联的。尝试执行与上面相同的练习,但使用不同的时间戳,您将看到key1的缩减值将根据应用缩减的顺序而有所不同

让我们看看这个:我们想用这个函数减少4,8和16,所以我们可能想这样做

((4 + 8) / 2 + 16) / 2
或作为

(4 + (8 + 16) / 2) / 2
根据我们在实际情况中是从左边还是从右边开始,还有更多不同的可能性,它们将发生在Spark中,因为您并不总是知道您的值在集群中是如何分布的

通过计算上述两种可能性,我们得到了不同的值:11和8,因此您可以看到,在实际案例中,这可能会导致更大的问题


在您的情况下,一个简单的解决方案是,假设所有时间戳都是长值,甚至是BigInteger,也要求和,以避免溢出,最后只除以值的数量,以获得实时平均值。

也许是时候创建一些表示JSON结构的case类了,然后你可以自己回答你的问题:好的,现在我有一个结构,它有3个文件。您建议将case类与struct aaa类似,并用objects变量替换f_2._2等?如果您的结构具有命名字段,则可读性更高,并且不会出现此类问题;嗯,我在阅读这段代码时没有问题,我知道每个f的意思,也知道上面提到的。我的问题在于理解,让我称之为多维reduceByKey,以及它在本例中是如何工作的。我读了很多关于这种方法的文章,但仍然无法整理出一些东西,这就是为什么我在这里寻求帮助:这太棒了,我欠你一大笔钱^^你向我解释了我需要的一切,关于进一步的datetime是Timestamp类型的,如果你对此有任何建议的话。非常感谢,我非常感谢:处理时间戳的最简单方法是使用getMillis或等效值,将时间戳更改为Long。
(4 + (8 + 16) / 2) / 2