核心
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();
    }
}