Spark SQL的DataFrame接口支持多种数据源的操作。一个DataFrame可以进行RDDs方式的操作,也可以被注册为临时表。把DataFrame注册为临时表之后,就可以对该DataFrame执行SQL查询。
Spark SQL的默认数据源为Parquet格式。数据源为Parquet文件时,Spark SQL可以方便的执行所有的操作。修改配置项spark.sql.sources.default,可修改默认数据源格式。
val df = spark.read.load("examples/src/main/resources/users.parquet")
df.select("name", "favorite_color").write.save("namesAndFavColors.parquet")
当数据源格式不是parquet格式文件时,需要手动指定数据源的格式。数据源格式需要指定全名(例如:org.apache.spark.sql.parquet),如果数据源格式为内置格式,则只需要指定简称定json, parquet, jdbc, orc, libsvm, csv, text来指定数据的格式。通过SparkSession提供的read.load方法用于通用加载数据,使用write和save保存数据。format指定读取和保存文件的格式
scala> df.write.format("parquet").save("file:///home/hadoop/out")
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
//查看数据是否保存
[hadoop@hadoop03 ~]$ cd out/
[hadoop@hadoop03 out]$ ls
part-00000-5056cc29-029f-4b95-822b-381da93faae3.snappy.parquet _SUCCESS
除此之外,可以直接运行SQL在文件上:
val sqlDF = spark.sql("SELECT * FROM parquet.hdfs://hadoop102:9000/namesAndAges.parquet")
sqlDF.show()
scala> val peopleDF = spark.read.format("json").load("examples/src/main/resources/people.json")
peopleDF: org.apache.spark.sql.DataFrame = [age: bigint, name: string]
scala> peopleDF.write.format("parquet").save("hdfs://hadoop102:9000/namesAndAges.parquet")
scala> peopleDF.show()
+----+-------+
| age| name|
+----+-------+
|null|Michael|
| 30| Andy|
| 19| Justin|
+----+-------+
scala> val sqlDF = spark.sql("SELECT * FROM parquet.hdfs:// hadoop102:9000/namesAndAges.parquet")
17/09/05 04:21:11 WARN ObjectStore: Failed to get database parquet, returning NoSuchObjectException
sqlDF: org.apache.spark.sql.DataFrame = [age: bigint, name: string]
scala> sqlDF.show()
+----+-------+
| age| name|
+----+-------+
|null|Michael|
| 30| Andy|
| 19| Justin|
+----+-------+
可以采用SaveMode执行存储操作,SaveMode定义了对数据的处理模式。需要注意的是,这些保存模式不使用任何锁定,不是原子操作。此外,当使用Overwrite方式执行时,在输出新数据之前原数据就已经被删除。SaveMode详细介绍如下表:
Scala/Java | Any Language | Meaning |
---|---|---|
SaveMode.ErrorIfExists(default) | “error”(default) | 如果文件存在,则报错 |
SaveMode.Append | “append” | 追加 |
SaveMode.Overwrite | “overwrite” | 覆写 |
SaveMode.Ignore | “ignore” | 数据存在,则忽略 |
Spark SQL 能够自动推测 JSON数据集的结构,并将它加载为一个Dataset[Row]. 可以通过SparkSession.read.json()去加载一个 一个JSON 文件。
//加载json文件
scala> val dsjson=spark.read.json("file:///home/hadoop/user.json")
dsjson: org.apache.spark.sql.DataFrame = [age: bigint, name: string]
//查看结构
scala> dsjson.printSchema()
root
|-- age: long (nullable = true)
|-- name: string (nullable = true)
//创建一张临时表
scala> dsjson.createOrReplaceTempView("stu")
//使用sparksql
scala> val jssql=spark.sql("select * from stu")
jssql: org.apache.spark.sql.DataFrame = [age: bigint, name: string]
//打印结果
scala> jssql.show()
+---+--------+
|age| name|
+---+--------+
| 12|zhangsan|
| 22| lisi|
| 11| wanger|
| 33| mazi|
+---+--------+
Parquet是一种流行的列式存储格式,可以高效地存储具有嵌套字段的记录。Parquet格式经常在Hadoop生态圈中被使用,它也支持Spark SQL的全部数据类型。Spark SQL 提供了直接读取和存储 Parquet 格式文件的方法。
scala> val par=spark.read.parquet("file:///home/hadoop/out/part.parquet")
par: org.apache.spark.sql.DataFrame = [age: bigint, name: string]
scala> par.createOrReplaceTempView("parquest")
scala> spark.sql("select * from parquest").show
+---+--------+
|age| name|
+---+--------+
| 12|zhangsan|
| 22| lisi|
| 11| wanger|
| 33| mazi|
+---+--------+
Spark SQL可以通过JDBC从关系型数据库中读取数据的方式创建DataFrame,通过对DataFrame一系列的计算后,还可以将数据再写回关系型数据库中。
注意:需要将相关的数据库驱动放到spark的类路径下。
(1)启动spark-shell
$ bin/spark-shell
(2)从Mysql数据库加载数据方式一
val jdbcDF = spark.read
.format("jdbc")
.option("url", "jdbc:mysql://hadoop102:3306/rdd")
.option("dbtable", "rddtable")
.option("user", "root")
.option("password", "000000")
.load()
(3)从Mysql数据库加载数据方式二
val connectionProperties = new Properties()
connectionProperties.put("user", "root")
connectionProperties.put("password", "000000")
val jdbcDF2 = spark.read
.jdbc("jdbc:mysql://hadoop102:3306/rdd", "rddtable", connectionProperties)
(4)将数据写入Mysql方式一
jdbcDF.write
.format("jdbc")
.option("url", "jdbc:mysql://hadoop102:3306/rdd")
.option("dbtable", "dftable")
.option("user", "root")
.option("password", "000000")
.save()
(5)将数据写入Mysql方式二
jdbcDF2.write.jdbc("jdbc:mysql://hadoop102:3306/rdd", "db", connectionProperties)
Apache Hive是Hadoop上的SQL引擎,Spark SQL编译时可以包含Hive支持,也可以不包含。包含Hive支持的Spark SQL可以支持Hive表访问、UDF(用户自定义函数)以及 Hive 查询语言(HiveQL/HQL)等。需要强调的一点是,如果要在Spark SQL中包含Hive的库,并不需要事先安装Hive。一般来说,最好还是在编译Spark SQL时引入Hive支持,这样就可以使用这些特性了。如果你下载的是二进制版本的 Spark,它应该已经在编译时添加了 Hive 支持。
若要把Spark SQL连接到一个部署好的Hive上,你必须把hive-site.xml复制到 Spark的配置文件目录中($SPARK_HOME/conf)。即使没有部署好Hive,Spark SQL也可以运行。 需要注意的是,如果你没有部署好Hive,Spark SQL会在当前的工作目录中创建出自己的Hive 元数据仓库,叫作 metastore_db。此外,如果你尝试使用 HiveQL 中的 CREATE TABLE (并非 CREATE EXTERNAL TABLE)语句来创建表,这些表会被放在你默认的文件系统中的 /user/hive/warehouse 目录中(如果你的 classpath 中有配好的 hdfs-site.xml,默认的文件系统就是 HDFS,否则就是本地文件系统)。
如果要使用内嵌的Hive,什么都不用做,直接用就可以了。
可以通过添加参数初次指定数据仓库地址:–conf spark.sql.warehouse.dir=hdfs://hadoop102/spark-wearhouse
注意:如果你使用的是内部的Hive,在Spark2.0之后,spark.sql.warehouse.dir用于指定数据仓库的地址,如果你需要是用HDFS作为路径,那么需要将core-site.xml和hdfs-site.xml 加入到Spark conf目录,否则只会创建master节点上的warehouse目录,查询时会出现文件找不到的问题,这是需要使用HDFS,则需要将metastore删除,重启集群。
如果想连接外部已经部署好的Hive,需要通过以下几个步骤。
将Hive中的hive-site.xml拷贝或者软连接到Spark安装目录下的conf目录下。
打开spark shell,注意带上访问Hive元数据库的JDBC客户端(如果提前将jar包放入了spark的lib目录中,就不用带上了)
$ bin/spark-shell --jars mysql-connector-java-5.1.40-bin.jar
重新进入spark-shell
scala> spark.sql("show databases").show
+------------+
|databaseName|
+------------+
| default|
| test_bd1906|
| test_shell|
|test_shell01|
+------------+
scala> spark.sql("use test_bd1906")
res2: org.apache.spark.sql.DataFrame = []
scala> spark.sql("show tables").show
+-----------+---------------+-----------+
| database| tableName|isTemporary|
+-----------+---------------+-----------+
|test_bd1906| a| false|
|test_bd1906| a1| false|
|test_bd1906| a2| false|
|test_bd1906| b| false|
|test_bd1906| stu_array| false|
|test_bd1906| stu_buk| false|
|test_bd1906| stu_partition| false|
|test_bd1906|stu_partiton_02| false|
|test_bd1906| student| false|
|test_bd1906| test_partition| false|
|test_bd1906| weibo| false|
|test_bd1906| weibo_10_t| false|
|test_bd1906| weibo_json| false|
|test_bd1906| weiboview| false|
+-----------+---------------+-----------+
Spark SQL CLI可以很方便的在本地运行Hive元数据服务以及从命令行执行查询任务。在Spark目录下执行如下命令启动Spark SQL CLI:
./bin/spark-sql
spark-sql (default)> show databases;
//打印:
databaseName
default
test_bd1906
test_shell
test_shell01
(1)添加依赖:
org.apache.spark
spark-hive_2.11
2.1.1
org.apache.hive
hive-exec
1.2.1
(2)创建SparkSession时需要添加hive支持(红色部分)
def main(args: Array[String]): Unit = {
val conf = new SparkConf().setMaster("local[*]").setAppName("hiveTemp")
//使用本地Hive,需要为使用内置Hive需要指定一个Hive仓库地址
val warehouseLocation: String = new File("spark-warehouse").getAbsolutePath
val spark = SparkSession
.builder()
.appName("hiveTemp")
.config("spark.sql.warehouse.dir", warehouseLocation)
.config(conf)
.enableHiveSupport()
.getOrCreate()
//使用外部Hive,需要将hive-site.xml添加到classpath路径下
// val spark = SparkSession
// .builder()
// .appName("hiveTemp")
// .config(conf)
// .enableHiveSupport()
// .getOrCreate()
spark.sql("create table if not exists tem(id int,user string) ")
}