Spark開發-SparkSql的開發

Xlucas發表於2017-09-28

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

相關文章