案例类映射到CSV

时间:2018-11-28 02:41:52

标签: scala apache-spark

cat department 
dept_id,dept_name
1,acc
2,finance
3,sales
4,marketing

为什么在df.show()和rdd.toDF.show()中使用show()时输出会有所不同。有人可以帮忙吗?

scala> case class Department (dept_id: Int, dept_name: String)
defined class Department

scala> val dept = sc.textFile("/home/sam/Projects/department")

scala> val mappedDpt = dept.map(p => Department( p(0).toInt,p(1).toString))

scala> mappedDpt.toDF.show()
+-------+---------+
|dept_id|dept_name|
+-------+---------+
|     49|        ,|
|     50|        ,|
|     51|        ,|
|     52|        ,|
+-------+---------+


scala> 

  val dept_df = spark.read
  .format("csv")
  .option("header","true")
  .option("inferSchema","true")
  .option("mode","permissive")
  .load("/home/sam/Projects/department")

  scala> dept_df.show()
+-------+---------+
|dept_id|dept_name|
+-------+---------+
|      1|      acc|
|      2|  finance|
|      3|    sales|
|      4|marketing|
+-------+---------+


scala> 

2 个答案:

答案 0 :(得分:1)

问题在这里

val mappedDpt = dept.map(p => Department( p(0).toInt,p(1).toString))

p是一个字符串,而不是 (您可能会想到)。为了更精确一点,p是文本文件的每一行,您可以确认已读过scaladoc

  

返回文本文件行的RDD”。

因此,当您应用apply方法(0)时,您正在按行上的位置访问字符。
这就是为什么从第一个字符的"49, ','"toInt 49结束的原因,该字符返回该行的字符的ascii值,并从该行的第二个字符返回','。 >

编辑

如果您需要重现read方法,可以执行以下操作:

object Department {
  /** The Option here is to handle errors. */
  def fromRawArray(data: Array[String]): Option[Department] = data match {
    case Array(raw_dept_id, dept_name) => Some(Department(raw_dept_id.toInt, dept_name))
    case _ => None
  }
}

// We use flatMap instead of map, to unwrap the values from the Option, the Nones get removed.
val mappedDpt = dept.flatMap(line => Department.fromRawArray(line.split(",")))

但是,我希望这只是为了学习。在生产代码上,应始终使用read版本。因为(处理缺失值,进行更好的类型转换等)会更健壮
例如,如果无法将第一个值强制转换为 Int ,则上述代码将引发异常。

答案 1 :(得分:0)

始终使用spark.read。*变体,因为它可以为您提供数据框,并且您也可以推断模式。

针对您的问题,在RDD版本中,您必须过滤第一行,然后使用逗号分隔符将行分开,然后可以将其映射到案例类Department。

一旦将其映射到Department,请注意,您正在创建类型化的数据框。因此它是一个数据集。所以你应该使用createDataset

下面的代码对我有用。

import org.apache.log4j.{Level, Logger}
import org.apache.spark.sql.SparkSession

object RDDSample {

  case class Department(dept_id: Int, dept_name: String)

  def main(args: Array[String]) {
    Logger.getLogger("org").setLevel(Level.ERROR)
    val spark = SparkSession.builder().appName("Spark_processing").master("local[*]").getOrCreate()

    import spark.implicits._

    val dept = spark.sparkContext.textFile("in/department.txt")
    val mappedDpt = dept.filter(line => !line.contains("dept_id")).map(p => {
      val y = p.split(","); Department(y(0).toInt, y(1).toString)
    })

    spark.createDataset(mappedDpt).show
  }
}

结果:

+-------+---------+
|dept_id|dept_name|
+-------+---------+
|      1|      acc|
|      2|  finance|
|      3|    sales|
|      4|marketing|
+-------+---------+