Scala 如何将来自mapPartitions的迭代器[String]结果写入一个文件?
我刚接触Spark和Scala,这就是为什么我很难度过这段时间的原因 我打算做的是使用Spark使用Stanford CoreNLP预处理我的数据。我知道我必须使用Scala 如何将来自mapPartitions的迭代器[String]结果写入一个文件?,scala,apache-spark,Scala,Apache Spark,我刚接触Spark和Scala,这就是为什么我很难度过这段时间的原因 我打算做的是使用Spark使用Stanford CoreNLP预处理我的数据。我知道我必须使用mapPartitions,以便按照中的建议为每个分区提供一个StanfordCoreNLP实例。然而,我缺乏知识/理解如何从这里开始 最后,我想在这些数据上训练字向量,但现在我很高兴知道如何从这里获得处理后的数据并将其写入另一个文件 到目前为止,我得到的是: import java.util.Properties import c
mapPartitions
,以便按照中的建议为每个分区提供一个StanfordCoreNLP
实例。然而,我缺乏知识/理解如何从这里开始
最后,我想在这些数据上训练字向量,但现在我很高兴知道如何从这里获得处理后的数据并将其写入另一个文件
到目前为止,我得到的是:
import java.util.Properties
import com.google.gson.Gson
import edu.stanford.nlp.ling.CoreAnnotations.{LemmaAnnotation, SentencesAnnotation, TokensAnnotation}
import edu.stanford.nlp.pipeline.{Annotation, StanfordCoreNLP}
import edu.stanford.nlp.util.CoreMap
import masterthesis.code.wordvectors.Review
import org.apache.spark.{SparkConf, SparkContext}
import scala.collection.JavaConversions._
object ReviewPreprocessing {
def main(args: Array[String]) {
val resourceUrl = getClass.getResource("amazon-reviews/reviews_Electronics.json")
val file = sc.textFile(resourceUrl.getPath)
val linesPerPartition = file.mapPartitions( lineIterator => {
val props = new Properties()
props.put("annotators", "tokenize, ssplit, pos, lemma")
val sentencesAsTextList : List[String] = List()
val pipeline = new StanfordCoreNLP(props)
val gson = new Gson()
while(lineIterator.hasNext) {
val line = lineIterator.next
val review = gson.fromJson(line, classOf[Review])
val doc = new Annotation(review.getReviewText)
pipeline.annotate(doc)
val sentences : java.util.List[CoreMap] = doc.get(classOf[SentencesAnnotation])
val sb = new StringBuilder();
sentences.foreach( sentence => {
val tokens = sentence.get(classOf[TokensAnnotation])
tokens.foreach( token => {
sb.append(token.get(classOf[LemmaAnnotation]))
sb.append(" ")
})
})
sb.setLength(sb.length - 1)
sentencesAsTextList.add(sb.toString)
}
sentencesAsTextList.iterator
})
System.exit(0)
}
}
例如,如何将该结果写入一个文件?排序在这里并不重要-我猜排序在这一点上无论如何都会丢失。如果您在
RDD
上使用saveAsTextFile
,您将拥有与您拥有的分区一样多的输出文件。为了只拥有一个分区,您可以将所有内容合并到一个分区中,如
sc.textFile("/path/to/file")
.mapPartitions(someFunc())
.coalesce(1)
.saveAsTextFile("/path/to/another/file")
或者(只是为了好玩),你可以把所有的分区一个一个地放到驱动程序中,然后自己保存所有的数据
val it = sc.textFile("/path/to/file")
.mapPartitions(someFunc())
.toLocalIterator
while(it.hasNext) {
writeToFile(it.next())
}
查看
RDD.saveAsTextFile
。谢谢!这很有效。问题是引发的另一个异常。结果仍然是一个目录/home/user/tmp/preprocessed.txt
,其中包含一个文件part-00000
,其中包含我感兴趣的实际内容。我想知道我如何命名^^我刚刚意识到,coalesce
将导致整个程序只在一个分区上运行。但不是在'someFunc()'之后-它只在一个分区上执行所有操作-这实际上不是我想要做的。不使用coalesce,您有多少个文件?它们可能很少,但可能只有一个已经写入了数据。要在合并之前对其进行转换,您必须“具体化”这一点-只需使用类似于count或smth的操作调用它。但是请注意,如果调用take(5),那么它将只处理第一个分区,因为只有一个分区就足以获得5条记录。在count()之前,必须缓存rdd以将其保留在spark worker节点的内存中。