Spark SQL 下DateFrame的初步认识(3)

概要:Spark SQL对数据的操作涉及到对数据的输入、输出,其实主要就是操作DataFrame。通过DataFrameReader的load方法可以创建DataFrame,通过DataFrameWriter的save方法可以把DataFrame中的数据保存到具体文件。我们可以通过设置具体的格式参数来指出读取的文件是什么类型,以及通过设置具体的格式参数来指出输出的文件是什么类型。

1, Spark SQL 加载数据流程

SQLContext中有load方法,实际上也就是使用了DataFrameReader的load方法。目前的Spark 1.6.0中,虽然SQLContext还有load方法,但已被设置为@deprecated。也就是说在Spark 2.0中SQLContext可能不再使用load方法。
DataFrameReader用来从外部存储系统(比如:文件系统,键值存储库,等等)读取数据,并返回DataFrame对象。
DataFrameReader有format方法,用来设置输入数据源的格式。
DataFrameReader用load方法,把外部数据加载进来,变成一个DataFrame。各种load方法,最终实际是使用以下load方法:

Spark SQL 下DateFrame的初步认识(3)_第1张图片
DataFrameReader的load方法是生成ResolvedDataSource对象,再使用该对象生成并返回一个DataFrame对象。
查看ResolvedDataSource的apply方法,可以发现其中是通过模式匹配来对各种类型的数据源分别进行处理,生成ResolvedDataSource对象。
查看ResolvedDataSource的backwardCompatibilityMap,可以知道,Spark SQL可以用来处理jdbc访问的数据库、json文件、parquet等多种来源的数据。
查看ResolvedDataSource的lookupDataSource方法,可以知道,Spark SQL可以处理Avro、Hive的ORC、访问Hadoop的文件系统等各种文件。
理论上讲,Spark SQL可以支持所有格式数据源。
DataFrame类中有this、toDF、printSchema、explain、show等常用方法。

2, Spark SQL保存数据

DataFrame中有各种save方法,实际上也就是使用了DataFrameWriter的save方法。
目前的Spark 1.6.0中虽然DataFrame还有save方法,但已被设置为@deprecated。也就是说在Spark 2.0中DataFrame可能不再使用save方法。
用以下程序SparkSQLLoadSaveOps.Java来演示Spark SQL 对数据的读取和保存:

package com.dt.spark.SparkApps.sql;

import org.apache.spark.SparkConf;
import org.apache.spark.api.java.JavaSparkContext;
import org.apache.spark.sql.DataFrame;
import org.apache.spark.sql.SQLContext;

/**
 * 用SparkSQL读取和保存数据。
 */
public class SparkSQLLoadSaveOps {
    public static void main(String[] args) {
        SparkConf conf = new SparkConf().setMaster("local").setAppName("RDD2DataFrameByProgrammatically");
        JavaSparkContext sc = new JavaSparkContext(conf);
        SQLContext sqlContext = new SQLContext(sc);

        DataFrame peopleDF = sqlContext.read().format("json").load("D:\\Big_Data_Software\\spark-1.6.0-bin-hadoop2.6\\examples\\src\\main\\resources\\people.json");
        peopleDF.select("name").write().format("json").save("D:\\Big_Data_Software\\spark-1.6.0-bin-hadoop2.6\\examples\\src\\main\\resources\\peopleNames.json");
    }
}

运行以上程序,可以发现会有相应的路径有文件输出

我们把代码中最后两行的format方法去掉,并修改源数据和目标数据路径:

DataFrame peopleDF = sqlContext.read().load("D:\\Big_Data_Software\\spark-1.6.0-bin-hadoop2.6\\examples\\src\\main\\resources\\users.parquet");
        peopleDF.select("name").write().save("D:\\Big_Data_Software\\spark-1.6.0-bin-hadoop2.6\\examples\\src\\main\\resources\\usersNames");

保存并运行程序,再看输出结果:

我们可以看到其中有Parquet文件。可见Spark SQL的缺省输出格式是Parquet。

我们仍然修改代码中最后两行,源数据使用json文件,输出时只增加mode方法以修改保存模式为追加:

DataFrame peopleDF = sqlContext.read().format("json").load("D:\\Big_Data_Software\\spark-1.6.0-bin-hadoop2.6\\examples\\src\\main\\resources\\people.json");
    peopleDF.select("name").write().mode(SaveMode.Append).save("D:\\Big_Data_Software\\spark-1.6.0-bin-hadoop2.6\\examples\\src\\main\\resources\\usersNames");

保存并运行程序,再看输出结果:

可以发现追加了parquet文件。

3, Spark SQL对数据处理的思考

业界的主流公司在做大数据分析的时候,基本上都以Parquet方式存储数据。Parquet文件是基于列式存储的,列之间是分开的,可以进行各种高效的优化。Spark底层一般都会接 Parquet文件。
Cloudera开发出了Kudu,Kudu是列式存储引擎,感觉似乎不错,但还不够稳定。Hadoop的HDFS有被替代的可能。
我们再来探究一下缺省输出格式是Parquet的原因。
先看一下DataFrameWriter.scala源码:
可以得出结论默认方式是parquet。

4,Spark SQL下的Parquet使用最佳实践

1, 过去整个业界对大数据的分析的技术栈的Pipeline一般分为以下两种方式:
a) Data Source->HDFS->MR/Hive/Spark(相当于ETL)->HDFS Parquet->Spark SQL/Impala->Result Service(可以放在DB中,也有可能被通过JDBC/ODBC来作为数据服务使用);
b) Data Source->Real time update data to HBase/DB->Export to Parquet->Spark SQL/Impala-> Result Service(可以放在DB中,也有可能被通过JDBC/ODBC来作为数据服务使用);
上述的第二种方式完全可以通过Kafka+Spark Streaming+Spark SQL(内部也强烈建议采用Parquet的方式来存储数据)的方式取代
2, 期待的方式:Data Source->Kafka->Spark Streaming->Parquet->Spark SQL(ML、GraphX等)->Parquet->其它各种Data Mining等

5,Parquet的精要介绍
1, Parquet是列式存储格式的一种文件类型,列式存储有以下的核心优势:
a.可以跳过不符合条件的数据,只读取需要的数据,降低IO数据量。
b.压缩编码可以降低磁盘存储空间。由于同一列的数据类型是一样的,可以使用更高效的压缩编码(例如Run Length Encoding和Delta Encoding)进一步节约存储空间。
c.只读取需要的列,支持向量运算,能够获取更好的扫描性能。

你可能感兴趣的:(Spark梦想)