使用Spark分区

时间:2016-10-29 18:39:12

标签: scala apache-spark

我是Spark的新手,并且有一些与Spark RDD操作和创建相关的问题:

val rdd1 =  sc.parallelize(List("yellow","red","blue","cyan","black"),3)
val mapped =   rdd1.mapPartitionsWithIndex{(index, iterator) => {
                                println("Called in Partition -> " + index)
                                val myList = iterator.toList
                                myList.map(x => x + " -> " + index).iterator
                               }
                            }

上述代码末尾的.iterator有什么用?它是否将列表转换为迭代器?列表本身不是一个迭代器,为什么我们最终需要这个操作呢? 另外,为什么这比普通的map()函数更快?它不是另一种逐元素工作方式,因为分区中的每个元素都再次使用map(x => x + " -> " + index)函数吗?

另一件事,我想通过一次读取4行文件来创建RDD。我在Scala中有以下代码:

val hconf = new org.apache.hadoop.conf.Configuration
hconf.set("mapreduce.input.lineinputformat.linespermap","4")
val line = sc.newAPIHadoopFile(inputFile,classOf[NLineInputFormat],classOf[LongWritable],classOf[Text],hconf).map(_._2.toString)
line.take(1).foreach(println)

但输出仍然只打印一行。由于我已将hconf设置为读取4行,因此RDD中的每个元素都不应接收4行inptFile吗?那么它不应该输出四行吗?

1 个答案:

答案 0 :(得分:3)

为什么要使用.iterator?

mapPartitions的函数参数是:

f: Iterator[T] => Iterator[U]

您粘贴的代码将每个迭代器转换为一个列表进行处理,并且需要在闭包结束时将其转换回迭代器以正确地进行类型检查。 Spark操作通常更喜欢流式传输数据,而不是一次性将所有数据都存储在内存中,并且强制包含Iterator的分区是该模型的一部分。

关于你的"列表是一个迭代器"断言,它并不完全正确 - 虽然ListIterable,但它不是IteratorIterator的特殊之处在于它们只能被使用一次,因此它们不支持许多标准的scala Collection操作。 IteratorIterable之间的主要区别在于这个"一次拍摄"模型:Iterable[T]可以根据需要多次生成Iterator[T],但如果您只有Iterator[T],则只能查看一次。

更高效的List - 免费实施

您粘贴的代码非常低效。您最终将所有数据复制到列表,然后从该列表生成迭代器。你可以只映射迭代器:

val rdd1 =  sc.parallelize(List("yellow","red","blue","cyan","black"),3)
val mapped =   rdd1.mapPartitionsWithIndex{(index, iterator) => {
                            println("Called in Partition -> " + index)
                            iterator.map(x => x + " -> " + index)
                           }
                        }  

每个地图的行数

我认为你可能在这里设置了错误的配置参数。有关可能的解决方案,请参阅this question