【一】SparkSQL數據源
【1】Spark SQL的DataFrame接口支持多種數據源的操作
一個DataFrame可以進行RDDs方式的操作,也可以被註冊爲臨時表,把DataFrame註冊爲臨時表之後,就可以對該DataFrame執行SQL查詢
【2】 Spark SQL的默認數據源爲Parquet格式
。數據源爲Parquet文件時,Spark SQL可以方便的執行所有的操作。修改配置項spark.sql.sources.default,可修改默認數據源格式
val df = sqlContext.read.load("examples/src/main/resources/users.parquet")
df.select("name", "favorite_color").write.save("namesAndFavColors.parquet")
【3】當數據源格式不是parquet格式文件時,需要手動指定數據源的格式。數據源格式需要指定全名(例如:org.apache.spark.sql.parquet),如果數據源格式爲內置格式,則只需要指定簡稱定json, parquet, jdbc, orc, libsvm, csv, text來指定數據的格式
可以通過SparkSession提供的read.load
方法用於通用加載數據,使用write
和save
保存數據
val df = spark.read.format("json").load("examples/src/main/resources/people.json")
df.write.format("json").save("hdfs://node01:8020/namesAndAges.json")
除此之外,可以直接運行SQL在文件上
val df= spark.sql("SELECT * FROM parquet.`hdfs://node01:8020/namesAndAges.json`")
df.show()
【4】文件保存選項
①.SaveMode.ErrorIfExists(default)
“error”(default) 如果文件存在,則報錯
②.SaveMode.Append
“append” 追加
③.SaveMode.Overwrite
“overwrite” 覆寫
④.SaveMode.Ignore
“ignore” 數據存在,則忽略
【5】Parquet文件
Parquet是一種流行的列式存儲格式,可以高效地存儲具有嵌套字段的記錄
【6】Parquet讀寫
Parquet格式經常在Hadoop生態圈中被使用,它也支持Spark SQL的全部數據類型。Spark SQL 提供了直接讀取和存儲 Parquet 格式文件的方法
import spark.implicits._
val peopleDF = spark.read.json("examples/src/main/resources/people.json")
peopleDF.write.parquet("hdfs://node01:8020/people.parquet")
val parquetFileDF = spark.read.parquet("hdfs://node01:8020/people.parquet")
parquetFileDF.createOrReplaceTempView("parquetFile")
val namesDF = spark.sql("SELECT name FROM parquetFile WHERE age BETWEEN 13 AND 19")
namesDF.map(attributes => "Name: " + attributes(0)).show()
【7】Schema合併
- 【1】像ProtocolBuffer、Avro和Thrift那樣,Parquet也支持Schema evolution(Schema演變)。用戶可以先定義一個簡單的Schema,然後逐漸的向Schema中增加列描述。通過這種方式,用戶可以獲取多個有不同Schema但相互兼容的Parquet文件。現在Parquet數據源能自動檢測這種情況,併合並這些文件的Schemas
- 【2】因爲Schema合併是一個高消耗的操作,在大多數情況下並不需要,所以Spark SQL從1.5.0開始默認關閉了該功能。可以通過下面兩種方式開啓該功能:
①.當數據源爲Parquet文件時,將數據源選項mergeSchema設置爲true
②.設置全局SQL選項spark.sql.parquet.mergeSchema爲true
import spark.implicits._
val df1 = sc.makeRDD(1 to 5).map(i => (i, i * 2)).toDF("single", "double")
df1.write.parquet("hdfs://node01:8020/data/test_table/key=1")
val df2 = sc.makeRDD(6 to 10).map(i => (i, i * 3)).toDF("single", "triple")
df2.write.parquet("hdfs://node01:8020/data/test_table/key=2")
val df3 = spark.read.option("mergeSchema","true")
.parquet("hdfs://master01:9000/data/test_table")
df3.printSchema()
- 【5】JSON數據集
Spark SQL 能夠自動推測 JSON數據集的結構,並將它加載爲一個DataSet[Row]. 可以通過SparkSession.read.json()去加載一個 DataSet[String]或者一個JSON 文件.注意,這個JSON文件不是一個傳統的JSON文件,每一行都得是一個JSON串
示例如下:👇
{"name":"Michael"}
{"name":"Andy", "age":30}
{"name":"Justin", "age":19}
- 【6】JDBC
Spark SQL可以通過JDBC從關係型數據庫中讀取數據的方式創建DataFrame,通過對DataFrame一系列的計算後,還可以將數據再寫回關係型數據庫中
注意,需要將相關的數據庫驅動放到spark的類路徑下
mysql-connector-java-5.1.38.jar
【讀取數據方式1】
val jdbcDF = spark.read.format("jdbc")
.option("url","jdbc:mysql://node01:3306/rdd")
.option("dbtable","user")
.option("user","root")
.option("password","root")
.load()
jdbcDF.show()
---------------------------------------------------------------------------------------------
【讀取數據方式2】
val connectionProperties = new java.util.Properties()
connectionProperties.put("user","root")
connectionProperties.put("password","root")
val jdbcDF2 = spark.read.jdbc("jdbc:mysql://node01:3306/rdd","user",connectionProperties)
jdbcDF2.show()
---------------------------------------------------------------------------------------------
【輸出數據方式2】
df.write.format("jdbc").mode("overwrite")
.option("url","jdbc:mysql://node01:3306/rdd")
.option("dbtable","user")
.option("user","root")
.option("password","root")
.save()
---------------------------------------------------------------------------------------------
【輸出數據方式2】
df.write.mode("overwrite").jdbc("jdbc:mysql://node01:3306/rdd","user",connectionProperties)
- 【7】運行Spark SQL CLI
Spark SQL CLI可以很方便的在本地運行Hive元數據服務以及從命令行執行查詢任務。需要注意的是,Spark SQL CLI不能與Thrift JDBC服務交互。
在Spark目錄下執行如下命令啓動Spark SQL CLI:
./bin/spark-sql
配置Hive需要替換 conf/ 下的 hive-site.xml
【9】Spark on Hive
- 【1】Apache Hive是Hadoop上的SQL引擎,Spark SQL編譯時可以包含Hive支持,也可以不包含。包含Hive支持的Spark SQL可以支持Hive表訪問、UDF(用戶自定義函數)以及 Hive 查詢語言(HiveQL/HQL)等。需要強調的 一點是,如果要在Spark SQL中包含Hive的庫,並不需要事先安裝Hive。一般來說,最好還是在編譯Spark SQL時引入Hive支持,這樣就可以使用這些特性了。如果你下載的是二進制版本的 Spark,它應該已經在編譯時添加了 Hive 支持。
- 【2】Spark on Hive即爲使用SparkSQL整合Hive,其實就是讓SparkSQL去加載Hive 的元數據庫,然後通過SparkSQL執行引擎去操作Hive表內的數據,所以首先需要開啓Hive的元數據庫服務,讓SparkSQL能夠加載元數據
配置
1)vim hive-site.xml
添加如下配置👇
<property>
<name>hive.metastore.warehouse.dir</name>
<value>/user/hive/warehouse</value>
</property>
<property>
<name>hive.metastore.local</name>
<value>false</value>
</property>
<property>
<name>hive.metastore.uris</name>
<value>thrift://hive所在節點主機名:9083</value>
</property>
2)後臺啓動 Hive MetaStore服務
hiveserver2 &
沒有配置hive.metastore.uris,開啓hiveserver2則會自動在本地啓動一個metastore
配置了hive.metastore.uris,則直接開啓metastore就可以讓SparkSQL連接到了
(重點就是開啓metastore,讓spark操作元數據)
或
nohup /export/servers/hive/bin/hive --service metastore 2>&1 >> /var/log.log &
3)SparkSQL整合Hive MetaStore
Spark 有一個內置的 Hive
,元數據
使用 Derby 嵌入式數據庫保存數據,在Spark根目錄下叫做metastore_db
,數據存放在Spark根目錄下的spark-warehouse
目錄中
SparkSQL 整合 Hive 的 MetaStore 主要思路就是要通過配置能夠訪問它, 並且能夠使用 HDFS 保存 wareHouse,所以可以直接拷貝 Hadoop 和 Hive 的配置文件到 Spark 的配置目錄
如下文件添加到Spark的conf目錄
hive-site.xml 元數據倉庫的位置等信息
core-site.xml 安全相關的配置
hdfs-site.xml HDFS 相關的配置
注:使用IDEA本地測試直接把以上配置文件放在resources目錄即可
使用IDEA操作hive時添加配置 .enableHiveSupport()//開啓hive語法的支持
代碼示例:
val spark = SparkSession
.builder()
.appName("Spark Hive Example")
.config(new SparkConf())
.enableHiveSupport()
.getOrCreate()
spark.sql("CREATE TABLE IF NOT EXISTS src (key INT, value STRING)")
spark.sql("LOAD DATA LOCAL INPATH 'examples/src/main/resources/kv1.txt' INTO TABLE src")
spark.sql("SELECT * FROM src").show()
spark.sql("SELECT COUNT(*) FROM src").show()
spark.close()
【10】SparkSQL輸出到MySQL
def main(args: Array[String]): Unit = {
/**
* 插入數據到MySQL
*/
val spark: SparkSession = SparkSession.builder()
.master("local[*]")
.appName("mysql")
.config(new SparkConf())
.getOrCreate()
val df: DataFrame = spark.read.json("user.json")
var prop = new Properties()
prop.setProperty("user","root")
prop.setProperty("password","root")
df.write.mode("overwrite").jdbc("jdbc:mysql://localhost:3306/tmp","user",prop)
spark.stop()
}
【11】SparkSQL讀取MySQL數據
def main(args: Array[String]): Unit = {
/**
* 從MySQL讀取數據
*/
val spark: SparkSession = SparkSession.builder()
.master("local[*]")
.appName("mysql")
.config(new SparkConf())
.getOrCreate()
var prop = new Properties()
prop.setProperty("user","root")
prop.setProperty("password","root")
val df: DataFrame = spark.read.jdbc("jdbc:mysql://localhost:3306/tmp","user",prop)
df.show()
spark.stop()
}