我是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吗?那么它不应该输出四行吗?
答案 0 :(得分:3)
mapPartitions
的函数参数是:
f: Iterator[T] => Iterator[U]
您粘贴的代码将每个迭代器转换为一个列表进行处理,并且需要在闭包结束时将其转换回迭代器以正确地进行类型检查。 Spark操作通常更喜欢流式传输数据,而不是一次性将所有数据都存储在内存中,并且强制包含Iterator
的分区是该模型的一部分。
关于你的"列表是一个迭代器"断言,它并不完全正确 - 虽然List
是Iterable
,但它不是Iterator
。 Iterator
的特殊之处在于它们只能被使用一次,因此它们不支持许多标准的scala Collection操作。 Iterator
和Iterable
之间的主要区别在于这个"一次拍摄"模型: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。