繁体   English   中英

在火花壳中使用mapPartitionsWithIndex将rowNumber()覆盖(partition_index)

[英]rowNumber() over(partition_index) using mapPartitionsWithIndex in spark-shell

我试图将分区索引和分区中的行号添加到rdd,并且做到了。 但是,当我尝试获取最后一个行号的值时,我得到的值为零,因此行号数组似乎未受影响。 可变范围问题?

就像rowNumber()/ count()over(partition_index)一样,但是在一个循环中将rownumber与分区索引一起添加了,所以效率更高吗?

代码如下:

scala> val rdd1 = sc.makeRDD(100 to 110)
rdd1: org.apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[32] at makeRDD at <console>:25

scala> val rownums=new Array[Int](3)
rownums: Array[Int] = Array(0, 0, 0)

scala> val rdd2=rdd1.repartition(3).mapPartitionsWithIndex( (idx, itr) => itr.map(r => (idx, {rownums(idx)+=1;rownums(idx)}, r)) )
rdd2: org.apache.spark.rdd.RDD[(Int, Int, Int)] = MapPartitionsRDD[37] at mapPartitionsWithIndex at <console>:29

scala> rdd2.collect.foreach(println)
(0,1,100)
(0,2,107)
(0,3,104)
(0,4,105)
(0,5,106)
(0,6,110)
(1,1,102)
(1,2,108)
(1,3,103)
(2,1,101)
(2,2,109)

scala> //uneffected??

scala> rownums.foreach(println)
0
0
0

scala> rownums
res20: Array[Int] = Array(0, 0, 0)

我期望rownums为(6,3,2):(


使用累加器解决:

scala> import org.apache.spark.util._
import org.apache.spark.util._

scala> val rownums=new Array[LongAccumulator](3)
rownums: Array[org.apache.spark.util.LongAccumulator] = Array(null, null, null)

scala> for(i <- 0 until rownums.length){rownums(i)=sc.longAccumulator("rownum_"+i)}

scala> val rdd1 = sc.makeRDD(100 to 110)
rdd1: org.apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[92] at makeRDD at <console>:124

scala> val rownums2=new Array[Int](3)
rownums2: Array[Int] = Array(0, 0, 0)

scala> val rdd2=rdd1.repartition(3).mapPartitionsWithIndex( (idx, itr) => itr.map(r => (idx, {rownums2(idx)+=1;rownums(idx).add(1);rownums2(idx)}, r)) )
rdd2: org.apache.spark.rdd.RDD[(Int, Int, Int)] = MapPartitionsRDD[97] at mapPartitionsWithIndex at <console>:130

scala> rdd2.collect.foreach(println)
(0,1,107)                                                                       
(0,2,106)
(0,3,105)
(0,4,110)
(0,5,104)
(0,6,100)
(1,1,102)
(1,2,103)
(1,3,108)
(2,1,109)
(2,2,101)

scala> rownums.foreach(x=>println(x.value))
6
3
2

scala> 

Spark在分布式系统中运行。 这意味着您无权修改函数外部的元素。

如果要获取包含每个分区的计数的数组,则需要将RDD转换为RDD[Int] ,其中每一行都是分区的计数,然后收集它。

rdd.mapPartitions(itr => Iterator(itr.size))

如果分区索引很重要,则可以创建RDD[Int,Int]并将其与行数一起包括在内。

rdd.mapPartitionsWithIndex((idx, itr) => Iterator((idx, itr.size)))

请阅读编程指南中的了解闭包

在执行之前,Spark计算任务的结束时间。 闭包是执行者在RDD上执行其计算所必须可见的那些变量和方法(在本例中为foreach())。 此闭包被序列化并发送给每个执行器。

发送给每个执行器的闭包中的变量现在是副本,因此,在foreach函数中引用计数器时,它不再是驱动程序节点上的计数器。 驱动程序节点的内存中仍然存在一个计数器,但是执行者将不再看到该计数器! 执行者仅从序列化闭包中看到副本。 因此,由于对计数器的所有操作都引用了序列化闭包内的值,所以计数器的最终值仍将为零。

您正在修改变量的本地副本,而不是原始变量。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM