核心
1、介绍SparkSQL中的2中RDD转换成DataFrame的方式
2、使用反射推理模式
3、以编程的方式指定schema
Spark SQL支持将现有RDD转换为DataFrames的两种不同方法。第一种方法使用反射来推断包含特定类型对象的RDD模式。当您在编写Spark应用程序时已经知道架构时,这种基于反射的方法会导致更简洁的代码,并且可以很好地运行。
创建DataFrames的第二种方法是通过编程接口,允许您构建一个模式,然后将其应用到现有的RDD。虽然这种方法更详细,但是当运行时列和它们的类型不知道时,它允许构造DataFrames。
1、使用反射推理模式
Spark SQL支持自动将JavaBeans的RDD 转换为DataFrame。使用反射获取的BeanInfo定义了表的模式。目前,Spark SQL不支持包含嵌套或包含复杂类型(如列表或数组)的JavaBean。您可以通过创建一个实现Serializable的类并为其所有字段设置getter和setter来创建JavaBean。
代码样例
package com.xlucas;
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.sql.DataFrame;
import org.apache.spark.sql.SQLContext;
import java.io.Serializable;
/**
* Created by xlucas on 2017-09-28.
* 使用反射推理模式
*/
public class SparkSql_Ser {
public static void main(String[] args){
SparkConf conf=new SparkConf();
conf.setAppName("Spark-Sql");
conf.setMaster("local");
//实例化SparkContext
JavaSparkContext sc=new JavaSparkContext(conf);
//实例化SQLContext
SQLContext sqlc=new SQLContext(sc);
//读取数据文件,并且将数据做map操作以后进行一个切分操作
JavaRDD<Person> person = sc.textFile("E://data//people.txt").map(new Function<String, Person>() {
@Override
public Person call(String line) throws Exception {
String[] parts=line.split(",");
Person p=new Person();
p.setName(parts[0]);
p.setAge(Integer.parseInt(parts[1].trim()));
return p;
}
});
//通过调用createDataFrame并提供JavaBean的Class对象,可以将模式应用于现有的RDD 。
DataFrame df=sqlc.createDataFrame(person,Person.class);
//将DataFrame注册到一个表里面
df.registerTempTable("people");
//DataFrame的编程
DataFrame df1=sqlc.sql("select * from people");
df1.show();
}
//创建一个实现Serializable的类
public static class Person implements Serializable{
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
}
2、以编程的方式指定schema
当JavaBean类不能被提前定义时(例如,记录的结构被编码为一个字符串,或者文本数据集将被解析,而对于不同的用户而言,字段的投射将不同),DataFrame可以通过三个步骤以编程方式创建一个。
1. Row从原始RDD 创建一个RDD;
2. 创建由在步骤1中创建的RDD中StructType匹配Rows 的结构所 表示的模式。
3. Row通过createDataFrame方法提供的方式将模式应用于RDD SQLContext。
代码样例
package com.xlucas;
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.sql.DataFrame;
import org.apache.spark.sql.Row;
import org.apache.spark.sql.RowFactory;
import org.apache.spark.sql.SQLContext;
import org.apache.spark.sql.types.DataType;
import org.apache.spark.sql.types.DataTypes;
import org.apache.spark.sql.types.StructField;
import org.apache.spark.sql.types.StructType;
import java.util.ArrayList;
import java.util.List;
/**
* Created by xlucas on 2017-09-28.
* 以编程的方式指定schema
*/
public class SparkSql_Str {
public static void main(String[] args){
//实例化SparkContext对象
SparkConf conf=new SparkConf();
conf.setAppName("Spark-sql");
conf.setMaster("local");
JavaSparkContext sc=new JavaSparkContext(conf);
//实例化SQLContext
SQLContext sqlc=new SQLContext(sc);
//读取数据文件
JavaRDD<String> line=sc.textFile("E://data//people.txt");
//构建schema的列表
String schema="name age";
List<StructField> fields=new ArrayList<StructField>();
//动态构造DataFrame的元数据,
for(String fieldName :schema.split(" ")){
fields.add(DataTypes.createStructField(fieldName,DataTypes.StringType,true));
}
// 也可以写成下面这种方式
//fields.add(DataTypes.createStructField("name",DataTypes.StringType,true));
//fields.add(DataTypes.createStructField("id",DataTypes.StringType,true));
//构建StructType,用于最后DataFrame元数据的描述
StructType sch =DataTypes.createStructType(fields);
// 在RDD的基础上创建类型为Row的RDD
JavaRDD<Row> rowRDD=line.map(new Function<String, Row>() {
@Override
public Row call(String s) throws Exception {
String[] Fields=s.split(",");
return RowFactory.create(Fields[0],Fields[1].trim());
}
});
// 基于已有的MetaData以及RDD<Row> 来构造DataFrame
DataFrame df=sqlc.createDataFrame(rowRDD,sch);
df.registerTempTable("people");
df.show();
}
}