Spark SQL的DataFrame接口支持多种数据源的操作。一个DataFrame可以进行RDDs方式的操作,也可以被注册为临时表。把DataFrame注册为临时表之后,就可以对该DataFrame执行SQL查询。Data Sources这部分首先描述了对Spark的数据源执行加载和保存的常用方法,然后对内置数据源进行深入介绍。
Spark SQL的默认数据源为Parquet格式。数据源为Parquet文件时,Spark SQL可以方便的执行所有的操作。修改配置项spark.sql.sources.default,可修改默认数据源格式。读取Parquet文件示例如下:
Dataset usersDF = spark.read().load("examples/src/main/resources/users.parquet");
usersDF.select("name", "favorite_color").write().save("namesAndFavColors.parquet");
当数据源格式不是parquet格式文件时,需要手动指定数据源的格式。数据源格式需要指定全名(例如:org.apache.spark.sql.parquet),如果数据源格式为内置格式,则只需要指定简称(json
, parquet
, jdbc
, orc
, libsvm
, csv
, text
)。通过指定的数据源格式名,可以对DataFrames进行类型转换操作。示例如下:
Dataset peopleDF =
spark.read().format("json").load("examples/src/main/resources/people.json");
peopleDF.select("name", "age").write().format("parquet").save("namesAndAges.parquet");
Dataset peopleDFCsv = spark.read().format("csv")
.option("sep", ";")
.option("inferSchema", "true")
.option("header", "true")
.load("examples/src/main/resources/people.csv");
Dataset sqlDF =
spark.sql("SELECT * FROM parquet.`examples/src/main/resources/users.parquet`");
可以采用SaveMode执行存储操作,SaveMode定义了对数据的处理模式。需要注意的是,这些保存模式不使用任何锁定,不是原子操作。此外,当使用Overwrite方式执行时,在输出新数据之前原数据就已经被删除。SaveMode详细介绍如下表:
Dataset peopleDF = spark.read().format("json")
.load("hdfs://spark1:9000/people.json");
peopleDF.save("hdfs://spark1:9000/people_savemode_test", "json", SaveMode.Append);
DataFrames
也可以使用 saveAsTable
命令作为 persistent tables (持久表)保存到 Hive metastore 中. 请注意, existing Hive deployment (现有的 Hive 部署)不需要使用此功能. Spark 将为您创建默认的 local Hive metastore (本地 Hive metastore)(使用 Derby ). 与 createOrReplaceTempView
命令不同, saveAsTable
将 materialize (实现) DataFrame 的内容, 并创建一个指向 Hive metastore 中数据的指针. 即使您的 Spark 程序重新启动, Persistent tables (持久性表)仍然存在, 因为您保持与同一个 metastore 的连接. 可以通过使用表的名称在 SparkSession
上调用 table
方法来创建 persistent tabl (持久表)的 DataFrame .
对于 file-based (基于文件)的 data source (数据源),例如 text, parquet, json等,您可以通过 path
选项指定 custom table path (自定义表路径), 例如 df.write.option("path", "/some/path").saveAsTable("t")
. 当表被 dropped (删除)时, custom table path (自定义表路径)将不会被删除,并且表数据仍然存在。如果未指定自定义表路径,Spark 将把数据写入 warehouse directory (仓库目录)下的默认表路径。当表被删除时, 默认的表路径也将被删除。
从 Spark 2.1 开始, persistent datasource tables (持久性数据源表)将 per-partition metadata (每个分区元数据)存储在 Hive metastore 中. 这带来了几个好处:
ALTER TABLE PARTITION ... SET LOCATION
现在可用于使用 Datasource API 创建的表。请注意,创建 external datasource tables (外部数据源表)(带有 path
选项)的表时,默认情况下不会收集 partition information (分区信息)。要 sync (同步) metastore 中的分区信息, 可以调用 MSCK REPAIR TABLE。
六、分桶,排序和分区
对于 file-based data source (基于文件的数据源), 也可以对 output (输出)进行 bucket 和 sort 或者 partition . Bucketing 和 sorting 仅适用于 persistent tables :
peopleDF.write().bucketBy(42, "name").sortBy("age").saveAsTable("people_bucketed");
在使用 Dataset API 时, partitioning 可以同时与 save
和 saveAsTable
一起使用。
usersDF
.write()
.partitionBy("favorite_color")
.format("parquet")
.save("namesPartByColor.parquet");
可以为 single table (单个表)使用 partitioning 和 bucketing:
peopleDF
.write()
.partitionBy("favorite_color")
.bucketBy(42, "name")
.saveAsTable("people_partitioned_bucketed");
partitionBy
创建一个 directory structure (目录结构), 如Partition Discovery部分所述. 因此, 对 cardinality (基数)较高的 columns 的适用性有限. 相反, bucketBy
可以在固定数量的 buckets 中分配数据, 并且可以在 a number of unique values is unbounded (多个唯一值无界时)使用数据。