SparkSQL外部資料來源

13545163656發表於2018-09-06

場景介紹:

    大資料MapReduce,Hive,Spark作業,首先需要載入資料,資料的存放源可能是HDFS、HBase、S3、OSS mongoDB;資料格式也可能為json、text、csv、parquet、jdbc..或者資料格式經過壓縮,不同格式檔案需要不同的解析方式,

    如果需要HDFS關聯MySQL資料,可以透過sqoop進行一些列轉換到,如果使用External Data Source API直接載入為DF拿到資料, 簡單的說可以透過SparkSQL拿到外部資料來源資料載入成DF。


載入方式:

build-in :內建載入外部資料如 json、text、parquet、jdbc、HDFS;


third-party:第三方載入外部資料如HBase、S3、OSS mongoDB

    第三方JAR地址:  

    Maven工程需要匯入gav

    spark-shell:需要外部匯入--package g:a:v  

 

    SPARK_HOME/bin/spark-shell --packages com.databricks:spark-csv_2.11:1.5.0

         優勢:下載依賴包到本地

缺點:內網環境沒有網路無法下載


一、外部資料來源讀取parquet檔案:

Spark context Web UI available at

Spark context available as 'sc' (master = local[2], app id = local-1536244013147).

Spark session available as 'spark'.

Welcome to

      ____              __

     / __/__  ___ _____/ /__

    _\ \/ _ \/ _ `/ __/  '_/

   /___/ .__/\_,_/_/ /_/\_\   version 2.3.1

      /_/

         

Using Scala version 2.11.8 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_45)

Type in expressions to have them evaluated.

Type :help for more information.


scala> spark.read.load("file:///home/hadoop/app/spark--bin-2.6.0-cdh5.7.0/examples/src/main/resources/people.txt").show

提示錯誤:/people.txt is not a Parquet file


注意:spark.read.load()底層預設讀取Parquet file

scala> spark.read.load("file:///home/hadoop/app/spark--bin-2.6.0-cdh5.7.0/examples/src/main/resources/users.parquet").show

18/09/06 10:32:29 WARN ObjectStore: Failed to get database global_temp, returning NoSuchObjectException

+------+--------------+----------------+                                        
|  name|favorite_color|favorite_numbers|
+------+--------------+----------------+
|Alyssa|          null|  [3, 9, 15, 20]|
|   Ben|           red|              []|
+------+--------------+----------------+

scala> val users = spark.read.load("file:///home/hadoop/app/spark--bin-2.6.0-cdh5.7.0/examples/src/main/resources/users.parquet")

users: org.apache.spark.sql.DataFrame = [name: string, favorite_color: string ... 1 more field]


scala> users.printSchema

root

 |-- name: string (nullable = true)

 |-- favorite_color: string (nullable = true)

 |-- favorite_numbers: array (nullable = true)

 |    |-- element: integer (containsNull = true)



scala> users.show

+------+--------------+----------------+
|  name|favorite_color|favorite_numbers|
+------+--------------+----------------+
|Alyssa|          null|  [3, 9, 15, 20]|
|   Ben|           red|              []|
+------+--------------+----------------+


-- 檢視列,常規操作

scala> users.select("name").show

+------+
|  name|
+------+
|Alyssa|
|   Ben|
+------+


二、轉換操作


-- 轉成json格式輸出

scala> users.select("name","favorite_color").write.format("json").save("file:////home/hadoop/data/parquet/")

[hadoop@hadoop001 parquet]$ cat *
{"name":"Alyssa"}
{"name":"Ben","favorite_color":"red"}


-- 不採取壓縮

.option("compression","none")  


-- 轉成text格式輸出

scala> users.select("name").write.format("text").save("file:////home/hadoop/data/parquet2/")

[hadoop@hadoop001 parquet2]$ cat *

Alyssa


-- Save Modes

用法:.mode("")

1、default   -- 目標目錄存在,丟擲異常

2、append   -- 目標目錄存在,重跑資料+1,無法保證資料冪等

3、overwrite -- 目標目錄存在,覆蓋原檔案

4、ignore -- 忽略你的模式,目標純在將不儲存


三、spark-shell操作JDBC資料

-- 讀取外部MySQL資料為DF

val jdbcDF = spark.read.format("jdbc").option("url", "jdbc:mysql://hadoop001:3306/ruozedata").option("driver","com.mysql.jdbc.Driver").option("dbtable", "city_info").option("user","root").option("password", "root").load()


-- 檢視錶資訊

jdbcDF.show()


-- 獲取本地資料 

val deptDF = spark.table("dept") 


-- join關聯使用

deptDF.join(jdbcDF,deptDF.col("deptid") === jdbcDF.col("deptid"))



-- DF寫入MySQL本地,資料型別有變化,重複寫入需要加上.mode("overwrite")

jdbcDF.write.format("jdbc").option("url", "jdbc:mysql://hadoop001:3306/hive_data").option("driver","com.mysql.jdbc.Driver").option("dbtable", "city_info_bak").option("user","root").option("password", "root").save()

mysql> show tables

+---------------------------+
| Tables_in_hive_data       |
+---------------------------+
| bucketing_cols            |
| cds                       |
| city_info_bak             |
+---------------------------+


-- 如果想型別不發生變化指定option指定欄位型別

.option("createTableColumnTypes", "name CHAR(64), comments VARCHAR(1024)")



四、spark-sql操作JDBC資料

-- SQL建立臨時表檢視,單session

CREATE TEMPORARY VIEW emp_sql
USING org.apache.spark.sql.jdbc
OPTIONS (
  url "jdbc:mysql://hadoop001:3306/ruozedata",
  dbtable "city_info",
  user 'root',
  password 'root'
)

show tbales;

INSERT INTO TABLE emp_sql

SELECT * FROM emp_sql



五、Perdicate Push Down(PPD)

               disk         network                  CPU

外部資料外(1T)------->獲取本地磁碟(1T)---------->提交到叢集(1T)--------->結果(1G)


               disk        network                   CPU

外部資料外(1T)------->經過列裁剪(10G)----------->提交到叢集(10G)----------->傳結果(1g)


               disk          CPU                 network

外部資料外(1T)------->經過列裁剪(10G)---------->進過計算(1G)----------->傳輸結果



六、SparkSQL外部資料來源實現機制

-- 0.有效的讀取外部資料來源的資料的


-- 1.buildScan掃描整張表,變成一個RDD[ROW]

trait TableScan {

def buildScan (): RDD[Row]  

}

-- 2.PrunedScan獲取表的裁剪列

trait PrunedScan {

def buildScan (requiredColumns: Array[String]): RDD[Row] 


-- 3.PrunedFilteredScan列裁剪,行過濾

trait PrunedFilteredScan {

def buildScan (requiredColumns: Array[String], filters: Array[Filter]): RDD[Row]


-- 4.載入外部資料來源的資料,定義資料的schema資訊

abstract class BaseRelation {


-- 5.Relation產生BaseRelation使用

trait RelationProvider

}



總歸:


-- 查詢類操作

trait PrunedScan {

  def buildScan (requiredColumns: Array[String]): RDD[Row]

}  

 

-- 列裁剪,行過濾

trait PrunedFilteredScan {

  def buildScan(requiredColumns: Array[String], filters: Array[Filter]): RDD[Row]

}  

-- 寫入類操作

trait InsertableRelation {

  def insert (data: DataFrame, overwrite: Boolean): Unit

}


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31441024/viewspace-2213714/,如需轉載,請註明出處,否則將追究法律責任。

相關文章