一:前置知识详解: 
Spark SQL重要是操作DataFrame,DataFrame本身提供了save和load的操作, 
Load:可以创建DataFrame, 
Save:把DataFrame中的数据保存到文件或者说与具体的格式来指明我们要读取的文件的类型以及与具体的格式来指出我们要输出的文件是什么类型。 
二:Spark SQL读写数据代码实战:

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.*;
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;

public class SparkSQLLoadSaveOps {
    public static void main(String[] args) {
        SparkConf conf = new SparkConf().setMaster("local").setAppName("SparkSQLLoadSaveOps");
        JavaSparkContext sc = new JavaSparkContext(conf);
        SQLContext = new SQLContext(sc);
        /**
         * read()是DataFrameReader类型,load可以将数据读取出来
         */
        DataFrame peopleDF = sqlContext.read().format("json").load("E:\\Spark\\Sparkinstanll_package\\Big_Data_Software\\spark-1.6.0-bin-hadoop2.6\\examples\\src\\main\\resources\\people.json");

        /**
         * 直接对DataFrame进行操作
         * Json: 是一种自解释的格式,读取Json的时候怎么判断其是什么格式?
         * 通过扫描整个Json。扫描之后才会知道元数据
         */
        //通过mode来指定输出文件的是append。创建新文件来追加文件
   peopleDF.select("name").write().mode(SaveMode.Append).save("E:\\personNames");
    }
}

读取过程源码分析如下: 
1. read方法返回DataFrameReader,用于读取数据。

[[DataFrameReader]] that can be used to read data in as a [[DataFrame]].
 * {{{
 *   sqlContext.read.parquet("/path/to/file.parquet")
 *   sqlContext.read.schema(schema).json("/path/to/file.json")
 * }}}
 *
 * @group genericdata
 * @since 1.4.0
 */
@Experimental
//创建DataFrameReader实例,获得了DataFrameReader引用
def read: DataFrameReader = new DataFrameReader(this)
2.  然后再调用DataFrameReader类中的format,指出读取文件的格式。

/**
 * Specifies the input data source format.
 *
 * @since 1.4.0
 */
def format(source: String): DataFrameReader = {
  this.source = source
  this
}
3.  通过DtaFrameReader中load方法通过路径把传入过来的输入变成DataFrame。

/**
 * Loads input in as a [[DataFrame]], for data sources that require a path (e.g. data backed by
 * a local or distributed file system).
 *
 * @since 1.4.0
 */
// TODO: Remove this one in Spark 2.0.
def load(path: String): DataFrame = {
  option("path", path).load()
}

至此,数据的读取工作就完成了,下面就对DataFrame进行操作。 
下面就是写操作!!! 
1. 调用DataFrame中select函数进行对列筛选

/**
 * Selects a set of columns. This is a variant of `select` that can only select
 * existing columns using column names (i.e. cannot construct expressions).
 *
 * {{{
 *   // The following two are equivalent:
 *   df.select("colA", "colB")
 *   df.select($"colA", $"colB")
 * }}}
 * @group dfops
 * @since 1.3.0
 */
@scala.annotation.varargs
def select(col: String, cols: String*): DataFrame = select((col +: cols).map(Column(_)) : _*)
2.  然后通过write将结果写入到外部存储系统中。

/**
 * :: Experimental ::
 * Interface for saving the content of the [[DataFrame]] out into external storage.
 *
 * @group output
 * @since 1.4.0
 */
@Experimental
def write: DataFrameWriter = new DataFrameWriter(this)
3. 在保持文件的时候mode指定追加文件的方式
/**
 * Specifies the behavior when data or table already exists. Options include:
// Overwrite是覆盖
 *   - `SaveMode.Overwrite`: overwrite the existing data.
//创建新的文件,然后追加
 *   - `SaveMode.Append`: append the data.
 *   - `SaveMode.Ignore`: ignore the operation (i.e. no-op).
 *   - `SaveMode.ErrorIfExists`: default option, throw an exception at runtime.
 *
 * @since 1.4.0
 */
def mode(saveMode: SaveMode): DataFrameWriter = {
  this.mode = saveMode
  this
}
4.   最后,save()方法触发action,将文件输出到指定文件中。

/**
 * Saves the content of the [[DataFrame]] at the specified path.
 *
 * @since 1.4.0
 */
def save(path: String): Unit = {
  this.extraOptions += ("path" -> path)
  save()
}

三:Spark SQL读写整个流程图如下:

四:对于流程中部分函数源码详解: 
DataFrameReader.Load() 
1. Load()返回DataFrame类型的数据集合,使用的数据是从默认的路径读取。

/**
 * Returns the dataset stored at path as a DataFrame,
 * using the default data source configured by spark.sql.sources.default.
 *
 * @group genericdata
 * @deprecated As of 1.4.0, replaced by `read().load(path)`. This will be removed in Spark 2.0.
 */
@deprecated("Use read.load(path). This will be removed in Spark 2.0.", "1.4.0")
def load(path: String): DataFrame = {
//此时的read就是DataFrameReader
  read.load(path)
}
2.  追踪load源码进去,源码如下:

在DataFrameReader中的方法。Load()通过路径把输入传进来变成一个DataFrame。

/**
 * Loads input in as a [[DataFrame]], for data sources that require a path (e.g. data backed by
 * a local or distributed file system).
 *
 * @since 1.4.0
 */
// TODO: Remove this one in Spark 2.0.
def load(path: String): DataFrame = {
  option("path", path).load()
}
3.  追踪load源码如下:
/**
 * Loads input in as a [[DataFrame]], for data sources that don't require a path (e.g. external
 * key-value stores).
 *
 * @since 1.4.0
 */
def load(): DataFrame = {
//对传入的Source进行解析
  val resolved = ResolvedDataSource(
    sqlContext,
    userSpecifiedSchema = userSpecifiedSchema,
    partitionColumns = Array.empty[String],
    provider = source,
    options = extraOptions.toMap)
  DataFrame(sqlContext, LogicalRelation(resolved.relation))
}

DataFrameReader.format() 
1. Format:具体指定文件格式,这就获得一个巨大的启示是:如果是Json文件格式可以保持为Parquet等此类操作。 
Spark SQL在读取文件的时候可以指定读取文件的类型。例如,Json,Parquet.

/**
 * Specifies the input data source format.Built-in options include “parquet”,”json”,etc.
 *
 * @since 1.4.0
 */
def format(source: String): DataFrameReader = {
  this.source = source //FileType
  this
}

DataFrame.write() 
1. 创建DataFrameWriter实例

/**
 * :: Experimental ::
 * Interface for saving the content of the [[DataFrame]] out into external storage.
 *
 * @group output
 * @since 1.4.0
 */
@Experimental
def write: DataFrameWriter = new DataFrameWriter(this)
2.  追踪DataFrameWriter源码如下:

以DataFrame的方式向外部存储系统中写入数据。

/**
 * :: Experimental ::
 * Interface used to write a [[DataFrame]] to external storage systems (e.g. file systems,
 * key-value stores, etc). Use [[DataFrame.write]] to access this.
 *
 * @since 1.4.0
 */
@Experimental
final class DataFrameWriter private[sql](df: DataFrame) {

DataFrameWriter.mode() 
1. Overwrite是覆盖,之前写的数据全都被覆盖了。 
Append:是追加,对于普通文件是在一个文件中进行追加,但是对于parquet格式的文件则创建新的文件进行追加。

**
 * Specifies the behavior when data or table already exists. Options include:
 *   - `SaveMode.Overwrite`: overwrite the existing data.
 *   - `SaveMode.Append`: append the data.
 *   - `SaveMode.Ignore`: ignore the operation (i.e. no-op).
//默认操作
 *   - `SaveMode.ErrorIfExists`: default option, throw an exception at runtime.
 *
 * @since 1.4.0
 */
def mode(saveMode: SaveMode): DataFrameWriter = {
  this.mode = saveMode
  this
}
2.  通过模式匹配接收外部参数
/**
 * Specifies the behavior when data or table already exists. Options include:
 *   - `overwrite`: overwrite the existing data.
 *   - `append`: append the data.
 *   - `ignore`: ignore the operation (i.e. no-op).
 *   - `error`: default option, throw an exception at runtime.
 *
 * @since 1.4.0
 */
def mode(saveMode: String): DataFrameWriter = {
  this.mode = saveMode.toLowerCase match {
    case "overwrite" => SaveMode.Overwrite
    case "append" => SaveMode.Append
    case "ignore" => SaveMode.Ignore
    case "error" | "default" => SaveMode.ErrorIfExists
    case _ => throw new IllegalArgumentException(s"Unknown save mode: $saveMode. " +
      "Accepted modes are 'overwrite', 'append', 'ignore', 'error'.")
  }
  this
}
DataFrameWriter.save() 
1. save将结果保存传入的路径。
/**
 * Saves the content of the [[DataFrame]] at the specified path.
 *
 * @since 1.4.0
 */
def save(path: String): Unit = {
  this.extraOptions += ("path" -> path)
  save()
}
2.  追踪save方法。
/**
 * Saves the content of the [[DataFrame]] as the specified table.
 *
 * @since 1.4.0
 */
def save(): Unit = {
  ResolvedDataSource(
    df.sqlContext,
    source,
    partitioningColumns.map(_.toArray).getOrElse(Array.empty[String]),
    mode,
    extraOptions.toMap,
    df)
}
3.  其中source是SQLConf的defaultDataSourceName

private var source: String = df.sqlContext.conf.defaultDataSourceName

其中DEFAULT_DATA_SOURCE_NAME默认参数是parquet。

// This is used to set the default data source
val DEFAULT_DATA_SOURCE_NAME = stringConf("spark.sql.sources.default",
  defaultValue = Some("org.apache.spark.sql.parquet"),
  doc = "The default data source to use in input/output.")

DataFrame.Scala中部分函数详解: 
1. toDF函数是将RDD转换成DataFrame

**
 * Returns the object itself.
 * @group basic
 * @since 1.3.0
 */
// This is declared with parentheses to prevent the Scala compiler from treating
// `rdd.toDF("1")` as invoking this toDF and then apply on the returned DataFrame.
def toDF(): DataFrame = this
2.  show()方法:将结果显示出来

/**
 * Displays the [[DataFrame]] in a tabular form. For example:
 * {{{
 *   year  month AVG('Adj Close) MAX('Adj Close)
 *   1980  12    0.503218        0.595103
 *   1981  01    0.523289        0.570307
 *   1982  02    0.436504        0.475256
 *   1983  03    0.410516        0.442194
 *   1984  04    0.450090        0.483521
 * }}}
 * @param numRows Number of rows to show
 * @param truncate Whether truncate long strings. If true, strings more than 20 characters will
 *              be truncated and all cells will be aligned right
 *
 * @group action
 * @since 1.5.0
 */
// scalastyle:off println
def show(numRows: Int, truncate: Boolean): Unit = println(showString(numRows, truncate))
// scalastyle:on println

追踪showString源码如下:showString中触发action收集数据。

/**
 * Compose the string representing rows for output
 * @param _numRows Number of rows to show
 * @param truncate Whether truncate long strings and align cells right
 */
private[sql] def showString(_numRows: Int, truncate: Boolean = true): String = {
  val numRows = _numRows.max(0)
  val sb = new StringBuilder
  val takeResult = take(numRows + 1)
  val hasMoreData = takeResult.length > numRows
  val data = takeResult.take(numRows)
  val numCols = schema.fieldNames.length
 

Spark SQL数据加载和保存实战的更多相关文章

  1. 3D Slicer中文教程(三)—数据加载及保存方式

    1.打开数据与保存数据 (1)打开数据 ——可以将数据拖拽到3D Slicer应用窗口或者从菜单栏工具栏打开. ——多种方式加载大量数据. 有关DICOM数据,请参阅DICOM模块文档. 对于几乎所有 ...

  2. spark SQL(三)数据源 Data Source----通用的数据 加载/保存功能

    Spark SQL 的数据源------通用的数据 加载/保存功能 Spark SQL支持通过DataFrame接口在各种数据源上进行操作.DataFrame可以使用关系变换进行操作,也可以用来创建临 ...

  3. Knockout应用开发指南 第六章:加载或保存JSON数据

    原文:Knockout应用开发指南 第六章:加载或保存JSON数据 加载或保存JSON数据 Knockout可以实现很复杂的客户端交互,但是几乎所有的web应用程序都要和服务器端交换数据(至少为了本地 ...

  4. 第六章:加载或保存JSON数据

    加载或保存JSON数据 Knockout可以实现很复杂的客户端交互,但是几乎所有的web应用程序都要和服务器端交换数据(至少为了本地存储需要序列化数据),交换数据最方便的就是使用JSON格式 – 大多 ...

  5. KnockoutJS 3.X API 第七章 其他技术(1) 加载和保存JSON数据

    Knockout允许您实现复杂的客户端交互性,但几乎所有Web应用程序还需要与服务器交换数据,或至少将本地存储的数据序列化. 最方便的交换或存储数据的方式是JSON格式 - 大多数Ajax应用程序今天 ...

  6. 6.Knockout.Js(加载或保存JSON数据)

    前言 Knockout可以实现很复杂的客户端交互,但是几乎所有的web应用程序都要和服务器端交换数据(至少为了本地存储需要序列化数据),交换数据最方便的就是使用JSON格式 – 大多数的Ajax应用程 ...

  7. Knockout.Js官网学习(加载或保存JSON数据)

    前言 Knockout可以实现很复杂的客户端交互,但是几乎所有的web应用程序都要和服务器端交换数据(至少为了本地存储需要序列化数据),交换数据最方便的就是使用JSON格式 – 大多数的Ajax应用程 ...

  8. 《利用python进行数据分析》读书笔记--第六章 数据加载、存储与文件格式

    http://www.cnblogs.com/batteryhp/p/5021858.html 输入输出一般分为下面几类:读取文本文件和其他更高效的磁盘存储格式,加载数据库中的数据.利用Web API ...

  9. AE数据加载

    1. 数据加载问题: 任何系统都离不开数据的加载,下边就AE中几种常用的数据加载做一个列举.以便查阅: 1.加载个人数据库 个人数据库是保存在Access中的数据库.其加载方式有两种:通过名字和通过属 ...

随机推荐

  1. canvas小球动画原理

    随着html5发展,canvas标签作为h5革命性的发展标志也越来越流行.canvas标签的强大之处,不仅在于它可以作为一个独立的画布,也可以利用canvas做一些动画而不用导入flash文件.同时, ...

  2. 基于 Koa平台Node.js开发的KoaHub.js的跳过组件代码

    koahub-skip koahub skip middleware koahub skip Conditionally skip a middleware when a condition is m ...

  3. loadrunner:判断是否服务器连接池瓶颈

    分析Web Resources中的Connections per second可以判断是否服务器连接池瓶颈. connections per second会给出两种不同状态的连接数:中断的连接和新建的 ...

  4. Python自动生产表情包

    作为一个数据分析师,应该信奉一句话--"一图胜千言".不过这里要说的并不是数据可视化,而是一款全民向的产品形态--表情包!!!! 表情包不仅仅是一种符号,更是一种文化--是促进社交 ...

  5. Android 事件统计

    title: Android 事件统计 1.写在前面的话 最近都在看framework的东西,也几天没有写什么东西,今天有点时间写下上次面试遇到的一个问题.问题大概是这样的,如果我需要统计页面的点击事 ...

  6. Redhat

    vm1 port:192.168.210.102 user:root;pwd:123456 user:openflowpwd:openflowKkm09!q esx4.1 server 安装一.修改I ...

  7. 开源的.NET定时任务组件Hangfire解析

    项目慢慢就要开工了,很多园友都在问这个事情,看来大伙对这事很上心啊,事情需要一步步的来,尽量写出一个我们都满意的项目.以前每次在博客前面都会扯淡一下,不过很多人都抱怨这样做不好,加上我这人扯淡起来就停 ...

  8. iOS回顾笔记(08) -- 自定义Cell的类型和创建步骤总结

    iOS回顾笔记(08) -- 自定义Cell的类型和创建步骤总结 项目中我们常见的自定义cell主要分为两种 等高cell:如应用列表.功能列表 非等高cell:如微博列表.QQ聊天页面 下面对这 ...

  9. SQL SERVER 执行大于80M的SQL 脚本

    在CMD控制器窗口 使用SqlCmd命令来执行 具体请看 SqlCmd /? 或者MSDN

  10. 前端学PHP之Session

    前面的话 Session技术和Cookie相似,都是用来储存使用者的相关资料.但最大的不同之处在于Cookie是将数据存放在客户端的计算机之中,而Session则是将数据存放于服务器系统之下.Sess ...