SparkSQL支持通过DataFrame接口操作多种数据源。DataFrame可以进行关系型转换操作,也能用来创建临时表。创建临时表后可以对它进行SQL查询。本章节描述了使用Spark数据源loading和saving数据的一般方法,然后是一些内建数据源的指定选项。
一般load/save函数
最简单的形式,使用默认数据源进行所有操作(默认是parquet,除非用spark.sql.sources.default进行了配置)。
Dataset<Row> usersDF = spark.read().load("examples/src/main/resources/users.parquet");
usersDF.select("name", "favorite_color").write().save("namesAndFavColors.parquet");
手动指定选项
可以手动指定数据源,并传入指定选项。数据源使用全限定名设置,如org.apache.spark.sql.parquet,对内建数据源也能使用简单名称(json, parquet, jdbc, orc, libsvm, csv, text),从任意数据源加载的DataFrame也能转换成其它类型。
加载json文件
Dataset<Row> peopleDF =
spark.read().format("json").load("examples/src/main/resources/people.json");
peopleDF.select("name", "age").write().format("parquet").save("namesAndAges.parquet");
加载csv文件
Dataset<Row> peopleDFCsv = spark.read().format("csv")
.option("sep", ";")
.option("inferSchema", "true")
.option("header", "true")
.load("examples/src/main/resources/people.csv");
执行写操作时也能使用额外选项,比如,可以为ORC数据源设置布隆过滤器和编码字典,下例在favorite_color上创建布隆过滤器,并且为name and favorite_color使用编码字典。
usersDF.write().format("orc")
.option("orc.bloom.filter.columns", "favorite_color")
.option("orc.dictionary.key.threshold", "1.0")
.save("users_with_options.orc");
在文件上直接运行SQL
Dataset<Row> sqlDF =
spark.sql("SELECT * FROM parquet.`examples/src/main/resources/users.parquet`");
保存模式
保存操作可设置SaveMode选项,指定如何处理存在的数据。要注意SaveMode没有用到锁,并不是原子性的。另外,执行Overwrite操作时,写出新数据前会先删除旧数据。
scala/java | 任意语言 | 含义 |
---|---|---|
SaveMode.ErrorIfExists(default) | error 或 errorIfExists(default) | 保存DataFrame时,如果已存在,抛出异常 |
SaveMode.Append | append | 保存DataFrame时,如果已存在,追加内容 |
SaveMode.Overwrite | overwrite | 保存DataFrame时,如果已存在,覆盖 |
SaveMode.Ignore | ignore | 保存DataFrame时,如果已存在,不做任何操作 |
保存为持久化表
DataFrame可以用saveAsTable命令向Hive metastore中存储为持久化表。注意用这个特性时不需要部署Hive,因为spark会创建一个默认的本地Hive metastore。
与createOrReplaceTempView命令不同,saveAsTable命令会显示DataFrame中的内容,并且创建一个指针指向Hive metastore中的数据。持久化表即使在spark程序重启后仍然存在。持久化表对应的DataFrame可以通过sparkSession的table方法创建,指定表的名称。
对基于文件的数据源,如text, parquet, json等,可以用path选项配置自定义表路径,df.write.option(“path”, “/some/path”).saveAsTable(“t”)。当table删掉时,自定义表路径不会删除,表数据仍然存在。没有指定路径时,spark会写到仓库目录下的默认路径中,删除表时,默认表路径也会被删除。
从spark2.1开始,持久化表会将每个分区的元数据存储到Hive metastore中,有一些好处:
- metastore可以只返回一个查询必要的分区,所以不需要先执行一个查询,返回所有的分区
- Hive的DDL操作,如ALTER TABLE PARTITION … SET LOCATION也可用了
Bucketing,Sorting,Partitioning
对文件数据源,可以对输出分桶,排序,分区。分桶和排序只能应用在持久化表。
peopleDF.write().bucketBy(42, "name").sortBy("age").saveAsTable("people_bucketed");
分区可在save和saveAsTable时使用:
usersDF
.write()
.partitionBy("favorite_color")
.format("parquet")
.save("namesPartByColor.parquet");
可以对一张表同时分桶分区
.write()
.partitionBy("favorite_color")
.bucketBy(42, "name")