[英]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.