使用反射来推断包含特定对象类型的RDD的模式(schema)。适用于写spark程序的同时,已经知道了模式,使用反射可以使得代码简洁。结合样本的名字,通过反射读取,作为列的名字。这个RDD可以隐式转化为一个SchemaRDD,然后注册为一个表。表可以在后续的sql语句中使用。
代码实现:
package com.wl.spark
import org.apache.spark.rdd.RDD
import org.apache.spark.sql.{DataFrame, SQLContext}
import org.apache.spark.{SparkConf, SparkContext}
/**
* desc:
* 通过反射来推断Schema
* 使用反射来推断包含特定对象类型的RDD的模式(schema)。
* Created by anmoFree on 2018/4/7
*/
class GenerateDFByClass {
}
object GenerateDFByClass{
def main(args: Array[String]): Unit = {
//创建SparkConf()并设置App名称和运行模式
val conf = new SparkConf().setAppName("GenerateDFByClass")
.setMaster("local")
// //SQLContext要依赖SparkContext
val sc = new SparkContext(conf)
// 创建SparkSql
val sqlContext = new SQLContext(sc);
// 从指定文件创建RDD
// 文件的每一行作为一个元组,组成元组的集合即为RDD
val fileRDD: RDD[String] = sc.textFile("F:/stu.txt")
// println(fileRDD.collect().toBuffer)
// 打印结果
// ArrayBuffer(101 tom 98, 102 jack 78, 103 lolo 80, 104 mark 67, 105 mary 88, 106 henry 89, 107 koko 70)
// println(fileRDD.foreach(x => println(x)))
/*
打印结果:
101 tom 98
102 jack 78
103 lolo 80
104 mark 67
105 mary 88
106 henry 89
107 koko 70
*/
// 切分数据
val lineRDD: RDD[Array[String]] = fileRDD.map(_.split(" "))
// 创建case class
// 将RDD和case class 关联
val stuRDD: RDD[Student] = lineRDD.map(x => Student(x(0).toInt, x(1), x(2).toInt))
// 导入隐式转换, 如果不导入无法将RDD转换为DataFrame
// 将RDD转换为DataFrame
import sqlContext.implicits._
val stuDF: DataFrame = stuRDD.toDF
// 将DataFrame注册为临时表
stuDF.registerTempTable("t_student")
// 对临时表进行操作
val df: DataFrame = sqlContext.sql("select * from t_student order by scores desc limit 2")
// 将结果以JSON的方式存储到指定文件夹
// df.write.json("F:/IO.txt")
/*
错误1:Exception in thread "main" org.apache.spark.sql.AnalysisException: path file:/F:/IO.txt already exists.;
F:/IO.txt 文件已存在 并且此处应该填写文件夹,会自动创建此文件夹并在文件夹下创建文件
*/
df.write.json("F:/result")
/*
结果:
{"id":101,"name":"tom","scores":98}
{"id":106,"name":"henry","scores":89}
*/
// 停止Spark Context
sc.stop()
}
}
// case class一定要放在伴生对象object外面
case class Student(id: Int, name: String, scores: Int)