了解地图功能的操作

时间:2017-11-20 11:42:46

标签: scala apache-spark rdd

我从书中找到了以下示例"使用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)

2 个答案:

答案 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()

时,你会得到它