spark學習筆記--Spark SQL

zxrui發表於2018-07-13

Spark SQL

enter image description here

  • Spark SQL可以從各種結構化資料來源(如JSON,Hive,Parquet等)中讀取資料
  • Spark SQL不僅支援在程式內進行SQL查詢,也支援從類似商業智慧軟體Tableau等這樣的外部工具通過資料庫聯結器(JDBC/ODBC)進行SQL查詢
  • Spark SQL 支援 SQL 與常規的 Python/Java/Scala 程式碼高度整合,包括連線 RDD 與 SQL 表、公開的自定義 SQL 函式介面等。

為了實現這些功能,Spark SQL提供了一種特殊的RDD,叫做SchemaRDD: - SchemaRDD是存放Row物件的RDD,每個Row物件代表一行記錄 - SchemaRDD還包含記錄的結構資訊(即資料欄位)

Spark SQL最強大之處就是可以在Spark應用內使用。這種方式讓我們可以輕鬆讀取資料並使用SQL查詢,同時還能把這一過程和普通的Python/Java/Scala程式程式碼結合在一起

Spark SQL是基於已有的SparkContext建立一個HiveContext,HiveContext可以建立出表示結構化資料的SchemalRDD,並且使用SQL或類似map()的普通RDD操作

Spark SQL的應用

scala:

// 匯入Spark SQL
import org.apache.spark.sql.hive.HiveContext
// 如果不能使用hive依賴的話
import org.apache.spark.sql.SQLContext

//匯入隱式轉換支援(隱式轉換被用來把帶有型別資訊的 RDD 轉變為專門用於 Spark SQL 查詢的 RDD(即SchemaRDD))
// 建立Spark SQL的HiveContext
val hiveCtx = ...
// 匯入隱式轉換支援
import hiveCtx._

//建立SQL上下文
val sc = new SparkContext(...)
val hiveCtx = new HiveContext(sc)

//查詢示例
val input = hiveCtx.jsonFile(inputFile)
// 註冊輸入的SchemaRDD
input.registerTempTable("tweets")
// 依據retweetCount(轉發計數)選出推文
val topTweets = hiveCtx.sql("SELECT text, retweetCount FROM
tweets ORDER BY retweetCount LIMIT 10")

SchemaRDD

從內部機理來看,SchemaRDD 是一個由 Row 物件組成的 RDD,附帶包含每列資料型別的結構資訊。Row 物件只是對基本資料型別(如整型和字串型等)的陣列的封裝。

SchemaRDD中可以儲存的資料型別 enter image description here

Row 物件表示 SchemaRDD 中的記錄,其本質就是一個定長的欄位陣列。

快取

Spark SQL 的快取機制與 Spark 中的稍有不同。由於我們知道每個列的型別資訊,所以 Spark 可以更加高效地儲存資料。
當快取資料表時,Spark SQL 使用一種列式儲存格式在記憶體中表示資料。這些快取下來的表只會在驅動器程式的生命週期裡保留在記憶體中,所以如果驅動器程式退出,就需要重新快取資料。和快取 RDD 時的動機一樣,如果想在同樣的資料上多次執行任務或查詢時,就應把這些資料表快取起來

讀取與儲存資料

  • Apache Hive

    當從 Hive 中讀取資料時,Spark SQL 支援任何 Hive 支援的儲存格式(SerDe),包括文字檔案、RCFiles、ORC、Parquet、Avro,以及 Protocol Buffer。

scala:

import org.apache.spark.sql.hive.HiveContext

val hiveCtx = new HiveContext(sc)
val rows = hiveCtx.sql("SELECT key, value FROM mytable")
val keys = rows.map(row => row.getInt(0))
  • Parquet

    Parquet(http://parquet.apache.org/)是一種流行的列式儲存格式,可以高效地儲存具有巢狀欄位的記錄。

scala:

//讀取資料
HiveContext.parquetFile 或者 SQLContext.parquetFile
//儲存資料
saveAsParquetFile()
  • JSON

    如果你有一個 JSON 檔案,其中的記錄遵循同樣的結構資訊,那麼 Spark SQL 就可以通過掃描檔案推測出結構資訊,並且讓你可以使用名字訪問對應欄位,而無需編寫專門的程式碼來讀取不同結構的檔案。

scala:

//讀取資料
val input = hiveCtx.jsonFile(inputFile)
  • 基於RDD建立SchemaRDD

    帶有 case class 的 RDD 可以隱式轉換成 SchemaRDD。

scala:

case class HappyPerson(handle: String, favouriteBeverage: String)
...
// 建立了一個人的物件,並且把它轉成SchemaRDD
val happyPeopleRDD = sc.parallelize(List(HappyPerson("holden", "coffee")))
// 注意:此處發生了隱式轉換
// 該轉換等價於sqlCtx.createSchemaRDD(happyPeopleRDD)
happyPeopleRDD.registerTempTable("happy_people")
  • 連線JDBC/ODBC伺服器

scala:

//啟動JDBC伺服器
./sbin/start-thriftserver.sh --master sparkMaster

//使用Spark自帶的Beelinek客戶端程式連線伺服器
holden@hmbp2:~/repos/spark$ ./bin/beeline -u jdbc:hive2://localhost:10000
Spark assembly has been built with Hive, including Datanucleus jars on classpath
scan complete in 1ms
Connecting to jdbc:hive2://localhost:10000
Connected to: Spark SQL (version 1.2.0-SNAPSHOT)
Driver: spark-assembly (version 1.2.0-SNAPSHOT)
Transaction isolation: TRANSACTION_REPEATABLE_READ
Beeline version 1.2.0-SNAPSHOT by Apache Hive
0: jdbc:hive2://localhost:10000> show tables;
+---------+
| result  |
+---------+
| pokes   |
+---------+
1 row selected (1.182 seconds)
0: jdbc:hive2://localhost:10000>

使用者自定義函式UDF

Spark SQL 不僅有自己的 UDF 介面,也支援已有的 Apache Hive UDF。

  • Spark SQL UDF

scala:

registerFunction("strLenScala", (_: String).length)
val tweetLength = hiveCtx.sql("SELECT strLenScala('tweet') FROM tweets LIMIT 10")
  • Hive UDF

標準的 Hive UDF 已經自動包含在了 Spark SQL 中。如果需要支援自定義的 Hive UDF,我們要確保該 UDF 所在的 JAR 包已經包含在了應用中。

scala:

//註冊Hive UDF
hiveCtx.sql("CREATE TEMPORARY FUNCTION name AS class.function")。

Spark SQL效能

Spark SQL中的效能選項

enter image description here

  • Beeline配置

scala:

beeline> set spark.sql.codegen=true;
SET spark.sql.codegen=true
spark.sql.codegen=true
Time taken: 1.196 seconds
  • Spark傳統配置

scala:

conf.set("spark.sql.codegen", "true")

配置說明:

  • spark.sql.codegen

  • 這個選項可以讓 Spark SQL 把每條查詢語句在執行前編譯為 Java 二進位制程式碼。由於生成了專門執行指定查詢的程式碼,codegen 可以讓大型查詢或者頻繁重複的查詢明顯變快。
  • 在執行特別快(1 ~ 2 秒)的即時查詢語句時,codegen 有可能會增加額外開銷,因為 codegen 需要讓每條查詢走一遍編譯的過程。
  • codegen 還是一個試驗性的功能,但是我們推薦在所有大型的或者是重複執行的查詢中使用 codegen。

  • spark.sql.inMemoryColumnarStorage.batchSize

在快取 SchemaRDD 時,Spark SQL 會按照這個選項制定的大小(預設值是 1000)把記錄分組,然後分批壓縮。太小的批處理大小會導致壓縮比過低,而批處理大小過大的話,也有可能引發記憶體問題。如果你表中的記錄比較大,你就可能需要調低批處理大小來避免記憶體不夠(OOM)的錯誤。如果不是在這樣的場景下,預設的批處理大小是比較合適的,因為壓縮超過 1000 條記錄時也基本無法獲得更高的壓縮比了。

相關文章