为什么要把RDD转换成DataSet呢因为那样的话,我们就可以直接针对于HDFS等任何可以构建为RDD的数据,使用sparkSql进行查询操作了。这个功能是无比强大的。想象一下针对与HDFS的数据直接就可以使用SQL进行查询。
spark支持两种方式将RDD转换成Dataset。
第一种方式,使用反射来推断包含了特定数据类型的RDD的元数据。这种基于反射的方式,代码比较简洁,当你已经知道了你的RDD的元数据时,是一种非常不错的方式。
第二种方式,是通过编程接口来创建DataFrame,你可以在程序运行时动态的构建一份元数据,然后将其应用到已经存在的RDD上这种方式代码比较冗长,但是在编写代码时还不知道元数据,只有在程序运行时才能动态的得知元数据,那么只有通过这种方式动态的构建元数据。
JAVA版本:SparkSQL 支持将包含了javaBean的RDD转换为DataSet 的。
JavaBean 的信息就定义了元数据。SparkSql 现在不支持将包含了嵌套的JavaBean 或者复杂的List 等复杂数据的JavaBean。作为元数据的,只支持包含简单的JavaBean.
Scala版本:
而scala由于其具有隐士转换的特性,所以SparkSql 的Scala 接口,是支持自动将包含了 case class 的RDD转换为DataSet 的case class 就定义了元数据, Spark Sql 会通过反射读取传递给case class的参数的名称,然后将其作为列名。与java 不同的是,Spark SQL 是支持将包含了嵌套数据结构的case class 作为元数据的比如包含了ARRAY 等等。
下面给出java 示例:
import com.wen.spark.sql.core.Bean.Student;
import org.apache.spark.SparkConf;
import org.apache.spark.api.java.JavaRDD;
import org.apache.spark.api.java.JavaSparkContext;
import org.apache.spark.api.java.function.Function;
import org.apache.spark.api.java.function.VoidFunction;
import org.apache.spark.sql.DataFrameReader;
import org.apache.spark.sql.Dataset;
import org.apache.spark.sql.Row;
import org.apache.spark.sql.SQLContext;
import org.mortbay.util.ajax.JSON;
import org.stringtemplate.v4.ST;
/**
* 使用反射的方式将RDD 转换为DataSet
*/
public class RDDToDataSetReflection {
public static void main(String[] args) {
SparkConf conf=new SparkConf().setMaster("local").setAppName("RDDToDataSetReflection");
JavaSparkContext sc=new JavaSparkContext(conf);
SQLContext sqlContext=new SQLContext(sc);
JavaRDD listRDD=sc.textFile("C:\\Users\\wchen129\\Desktop\\data\\sparkdata\\students.json");
JavaRDD listStudent=listRDD.map(new Function() {
@Override
public Student call(String s) throws Exception {
Student student = com.alibaba.fastjson.JSONObject.parseObject(s,Student.class);
return student;
}
});
//使用反射的方式将RDD 转成为 DataFrame
Dataset studentData=sqlContext.createDataFrame(listStudent,Student.class);
//拿到一个DataSet 后就可以将其注册成为一个零时表,然后针对于之中的数据进行Sql 语句
studentData.show();
studentData.registerTempTable("students");
//针对于 students 执行sql 语句操作
Dataset teenagerDF=sqlContext.sql("select * from students where age <19");
//展示出查询的数据
teenagerDF.show();
//将查询出的DataFrame 再一次转化为RDD
JavaRDD teenagerRDD=teenagerDF.javaRDD();
//将RDD 中的数据进行映射转换成为Student
JavaRDD result=teenagerRDD.map(new Function() {
@Override
public Student call(Row row) throws Exception {
Student student=new Student();
student.setId(row.getInt(1));
student.setName(row.getString(2));
student.setAge(row.getInt(0));
return student;
}
});
result.foreach(new VoidFunction() {
@Override
public void call(Student student) throws Exception {
System.out.println(student.toString());
}
});
sc.close();
}
}
下面给出scala 示例:
object RDDToDataSetReflection {
def main(args: Array[String]): Unit = {
val conf = new SparkConf().setMaster("local").setAppName("RDDToDataSetReflection")
val sc = new JavaSparkContext(conf)
val sqlContext = new SQLContext(sc)
val listRDD = sc.textFile("C:\\Users\\wchen129\\Desktop\\data\\sparkdata\\students.json")
val listStudent = listRDD.map(new Function[String, Student]() {
@throws[Exception]
override def call(s: String): Student = {
val student = com.alibaba.fastjson.JSON.parseObject(s, classOf[Student])
// var string=s.split(",")
// var student=new Student;
// student.setId(Integer.valueOf(string(0).trim()))
// student.setAge(Integer.valueOf(string(2).trim()))
// student.setName(string(1))
student
}
})
//使用反射的方式将RDD 转成为 DataFrame
val studentData = sqlContext.createDataFrame(listStudent, classOf[Student])
//拿到一个DataSet 后就可以将其注册成为一个零时表,然后针对于之中的数据进行Sql 语句
studentData.show()
studentData.registerTempTable("students")
//针对于 students 执行sql 语句操作
val teenagerDF = sqlContext.sql("select * from students where age <19")
//展示出查询的数据
teenagerDF.show()
//将查询出的DataFrame 再一次转化为RDD
val teenagerRDD = teenagerDF.javaRDD
//将RDD 中的数据进行映射转换成为Student
val result = teenagerRDD.map(new Function[Row, Student]() {
@throws[Exception]
override def call(row: Row): Student = {
new Student(row.getInt(1),row.getString(2),row.getInt(0))
}
})
result.foreach(new VoidFunction[Student]() {
@throws[Exception]
override def call(student: Student): Unit = {
System.out.println(student.toString)
}
})
sc.close()
}
}
通过编程接口来创建DataFrame,你可以在程序运行时动态的构建一份元数据,然后将其应用到已经存在的RDD上这种方式代码比较冗长,但是在编写代码时还不知道元数据,只有在程序运行时才能动态的得知元数据,那么只有通过这种方式动态的构建元数据。
下面给出java 示例
public static void main(String[] args) {
SparkConf conf=new SparkConf().setMaster("local").setAppName("RDDToDataSetReflection");
JavaSparkContext sc=new JavaSparkContext(conf);
SQLContext sqlContext=new SQLContext(sc);
JavaRDD listRDD=sc.textFile("C:\\Users\\wchen129\\Desktop\\data\\sparkdata\\students.txt");
//第一步创建RDD 但是需要转换成RDD
JavaRDD rowRDD=listRDD.map(new Function() {
@Override
public Row call(String s) throws Exception {
String[] string=s.split(",");
return RowFactory.create(Integer.parseInt(string[0]),string[1],Integer.parseInt(string[2]));
}
});
//动态构建元数据
List fields=new ArrayList();
fields.add(DataTypes.createStructField("id", DataTypes.IntegerType,true));
fields.add(DataTypes.createStructField("name", DataTypes.StringType,true));
fields.add(DataTypes.createStructField("age", DataTypes.IntegerType,true));
StructType structType=DataTypes.createStructType(fields);
// 第三部将使用动态的元数据,将RDD 转换为DataSet
Dataset studentFD=sqlContext.createDataFrame(rowRDD,structType);
//后面就可以使用DataSet
studentFD.registerTempTable("students");
Dataset teenagerFD=sqlContext.sql("select * from students where age<19 ");
List rows=teenagerFD.javaRDD().collect();
for(Row row:rows){
System.out.println(row);
}
}
下面给出scala 示例
object RDDToDataSetProgrammatically {
def main(args: Array[String]): Unit = {
val conf = new SparkConf().setMaster("local").setAppName("RDDToDataSetReflection")
val sc = new JavaSparkContext(conf)
val sqlContext = new SQLContext(sc)
val listRDD = sc.textFile("C:\\Users\\wchen129\\Desktop\\data\\sparkdata\\students.txt")
//第一步创建RDD 但是需要转换成RDD
val rowRDD = listRDD.map(new Function[String, Row]() {
@throws[Exception]
override def call(s: String): Row = {
val string = s.split(",")
RowFactory.create(string(0).toInt, string(1), string(2).toInt)
}
})
//动态构建元数据
val fields = new util.ArrayList[StructField]
fields.add(DataTypes.createStructField("id", DataTypes.IntegerType, true))
fields.add(DataTypes.createStructField("name", DataTypes.StringType, true))
fields.add(DataTypes.createStructField("age", DataTypes.IntegerType, true))
val structType = DataTypes.createStructType(fields)
// 第三部将使用动态的元数据,将RDD 转换为DataSet
val studentFD = sqlContext.createDataFrame(rowRDD, structType)
//后面就可以使用DataSet
studentFD.registerTempTable("students")
val teenagerFD = sqlContext.sql("select * from students where age<19 ")
val rows = teenagerFD.javaRDD.collect
import scala.collection.JavaConversions._
for (row <- rows) {
System.out.println(row)
}
}
}