【Spark】SparkSQL入門解析(二)

在這裏插入圖片描述

【一】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方法用於通用加載數據,使用writesave保存數據

	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()
  }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章