我从书中找到了以下示例"使用Spark快速处理"作者:Holden Karau。我不明白以下代码行在程序中的作用:
val splitLines = inFile.map(line => {
val reader = new CSVReader(new StringReader(line))
reader.readNext()
})
val numericData = splitLines.map(line => line.map(_.toDouble))
val summedData = numericData.map(row => row.sum)
该计划是:
package pandaspark.examples
import spark.SparkContext
import spark.SparkContext._
import spark.SparkFiles;
import au.com.bytecode.opencsv.CSVReader
import java.io.StringReader
object LoadCsvExample {
def main(args: Array[String]) {
if (args.length != 2) {
System.err.println("Usage: LoadCsvExample <master>
<inputfile>")
System.exit(1)
}
val master = args(0)
val inputFile = args(1)
val sc = new SparkContext(master, "Load CSV Example",
System.getenv("SPARK_HOME"),
Seq(System.getenv("JARS")))
sc.addFile(inputFile)
val inFile = sc.textFile(inputFile)
val splitLines = inFile.map(line => {
val reader = new CSVReader(new StringReader(line))
reader.readNext()
})
val numericData = splitLines.map(line => line.map(_.toDouble))
val summedData = numericData.map(row => row.sum)
println(summedData.collect().mkString(","))
}
}
我简要了解上述程序的功能。它解析输入 CSV并汇总所有行。但是这3行代码究竟是如何实现的,这是我无法理解的。
也可以解释一下如果用flatMap替换这些行会如何改变输出?像:
val splitLines = inFile.flatMap(line => {
val reader = new CSVReader(new StringReader(line))
reader.readNext()
})
val numericData = splitLines.flatMap(line => line.map(_.toDouble))
val summedData = numericData.map(row => row.sum)
答案 0 :(得分:1)
首先,您的代码示例中没有任何flatMap
操作,因此标题具有误导性。但通常map
调用集合会返回新集合,其函数应用于集合的每个元素。
逐行浏览您的代码段:
val splitLines = inFile.map(line => {
val reader = new CSVReader(new StringReader(line))
reader.readNext()
})
inFile
的类型为RDD[String]
。你接受每个这样的字符串,从中创建csv reader并调用readNext
(返回字符串数组)。所以最后你会得到RDD[String[]]
。
val numericData = splitLines.map(line => line.map(_.toDouble))
嵌套了2个贴图操作,有点棘手。再次,您获取RDD集合的每个元素(现在是String[]
)并将_.toDouble
函数应用于String[]
的每个元素。最后,您将获得RDD[Double[]]
。
val summedData = numericData.map(row => row.sum)
您使用RDD元素并将sum
函数应用于它们。由于每个元素都是Double[]
,因此sum将生成单个Double
值。最后,您将获得RDD[Double]
。
答案 1 :(得分:1)
val splitLines = inFile.map(line => {
val reader = new CSVReader(new StringReader(line))
reader.readNext()
})
val numericData = splitLines.map(line => line.map(_.toDouble))
val summedData = numericData.map(row => row.sum)
所以在这段代码中基本上是读取CSV文件数据并添加它的值。 假设您的CSV文件类似于 -
10,12,13
1,2,3,4
1,2
所以这里inFile我们从CSV文件中获取数据,如 -
val inFile = sc.textFile("your CSV file path")
所以这里inFile是一个RDD,它有文本格式的数据。 当你对它应用收集时,它将看起来像这样 -
Array[String] = Array(10,12,13 , 1,2,3,4 , 1,2)
当你在地图上应用地图时,你会发现 -
line = 10,12,13
line = 1,2,3,4
line = 1,2
并且以CSV格式读取此数据时,它正在使用 -
val reader = new CSVReader(new StringReader(line))
reader.readNext()
所以在读取CSV格式的数据后,splitLines看起来像 -
Array(
Array(10,12,13),
Array(1,2,3,4),
Array(1,2)
)
在splitLines上,它正在应用
splitLines.map(line => line.map(_.toDouble))
在这里你将得到数组(10,12,13),之后,它正在使用
line.map(_.toDouble)
所以它将所有元素类型从字符串更改为Double。 所以在numericData中你会得到相同的
Array(Array(10.0, 12.0, 13.0), Array(1.0, 2.0, 3.0, 4.0), Array(1.0, 2.0))
但所有元素现在都是Double
形式并且它正在应用单个行或数组的总和,所以回答类似的事情 - 数组(35.0,10.0,3.0)
当你申请susummedData.collect()
时,你会得到它