一、Spark SQL 概述
1.1 什麼是Spark SQL
Spark SQL
是 Spark
用來處理結構化資料的一個模組,它提供了2個程式設計抽象:
DataFrame
和DataSet
,並且作為分散式 SQL 查詢引擎的作用。
以 Hive
作為對比,Hive
是將 Hive SQL
轉換成 MapReduce
然後提交到叢集上執行,大大簡化了編寫 MapReduce
的程式的複雜性,由於 MapReduce
這種計算模型執行效率比較慢。所有Spark SQL
的應運而生,它是將 Spark SQL
轉換成 RDD
,然後提交到叢集執行,執行效率非常快。
1.2 Spark SQL 的特點
這裡引用 Spark 官網:
① 易整合
② 統一的資料訪問方式
③ 相容Hive
④ 標準的資料連線
1.3 什麼是 DataFrame
在 Spark
中,DataFrame
是一種以 RDD
為基礎的分散式資料集,類似於傳統資料庫中的二維表格。
DataFrame
與 RDD
的主要區別在於,前者帶有 schema
元資訊,即 DataFrame
所表示的二維表資料集的每一列都帶有名稱和型別。這使得 Spark SQL
得以洞察更多的結構資訊,從而對藏於DataFrame
背後的資料來源以及作用於 DataFrame
之上的變換進行了針對性的優化,最終達到大幅提升執行時效率的目標。
反觀 RDD
,由於無從得知所存二維資料的內部結構,Spark Core
只能在 stage
層面進行簡單、通用的流水線優化。
圖示
DataFrame
也是懶執行的,但效能上比 RDD
要高,主要原因:
優化的執行計劃,即查詢計劃通過 Spark Catalyst Optimiser
進行優化。比如下面一個例子:
看看 Spark Core
和 Spark SQL
模組對這個計劃的執行步驟:
1.4 什麼是 DataSet
DataSet
也是分散式資料集合。
DataSet
是 Spark 1.6
中新增的一個新抽象,是 DataFrame
的一個擴充套件。它提供了 RDD
的優勢(強型別,使用強大的 Lambda
函式的能力)以及 Spark SQL
優化執行引擎的優點,DataSet
也可以使用功能性的轉換(操作 map
,flatMap
,filter
等等)。
具體的優勢如下:
1)是 DataFrame API
的一個擴充套件,SparkSQL
最新的資料抽象;
2)使用者友好的 API
風格,既具有型別安全檢查也具有 DataFrame
的查詢優化特性;
3)用樣例類來對 DataSet
中定義資料的結構資訊,樣例類中每個屬性的名稱直接對映到 DataSet
中的欄位名稱;
4)DataSet
是強型別的。比如可以有 DataSet[Car]
,DataSet[Person]
二、Spark SQL 程式設計
2.1 SparkSession
在老的版本中,Spark SQL
提供兩種 SQL
查詢起始點:一個叫 SQLContext
,用於 Spark
自己提供的 SQL
查詢;一個叫 HiveContext
,用於連線 Hive
的查詢。
SparkSession
是 Spark
最新的 SQL
查詢起始點,實質上是 SQLContext
和 HiveContext
的組合,所以在 SQLContex
和 HiveContext
上可用的 API
在 SparkSession
上同樣是可以使用的。
SparkSession
內部封裝了 SparkContext
,所以計算實際上是由 SparkContext
完成的。
2.2 DataFrame
1. 建立
在 Spark SQL
中 SparkSession
是建立 DataFrame
和執行 SQL
的入口,建立 DataFrame
有三種方式
- 通過
Spark
的資料來源進行建立; - 從一個存在的
RDD
進行轉換; - 還可以從
Hive Table
進行查詢返回
通過 Spark 的資料來源進行建立
- 檢視
Spark
資料來源進行建立的檔案格式
- 讀取官網提供的
json
檔案建立DataFrame
- 從
RDD
轉換(詳見 2.5 節) - 從
Hive Table
轉換(詳見 3.3節)
2. SQL 風格語法(主要)
直接通過 SQL
語句對 DataFrame
的資料進行操作
- 建立一個
DataFrame
- 對
DataFrame
建立一個臨時表
建立臨時表的三種方式
- 通過
SQL
語句實現查詢全表
注意:普通臨時表是 Session
範圍內的,如果想應用範圍內有效,可以使用全域性臨時表。使用全域性臨時表時需要全路徑訪問,如:global_temp.people
- 對於
DataFrame
建立一個全域性表
df.createGlobalTempView("people")
複製程式碼
- 通過
SQL
語句實現查詢全表
spark.sql("SELECT * FROM global_temp.people").show()
複製程式碼
spark.newSession().sql("SELECT * FROM global_temp.people").show()
複製程式碼
以上兩行程式碼的執行效果一致~
3. DSL 風格語法(次要)
使用更為簡潔的語法對 DataFrame
的資料操作
-
建立一個
DataFrame
(同上) -
檢視
DataFrame
的Schema
資訊
- 只檢視
name
列資料
- 檢視
name
列資料以及age+1
資料
- 檢視
age
大於21
的資料
- 按照
age
分組,檢視資料條數
個人感覺簡單的操作可以使用 DSL
,複雜查詢再使用 SQL
是一個很不錯的方案
注意:DSL
方法由 DataFrame
呼叫,而 SQL
由 SparkSession
呼叫
4. RDD 轉換為 DateFrame
注意:如果需要 RDD
與 DF
或者 DS
之間操作,那麼都需要引入 import spark.implicits._
【spark不是包名,而是 SparkSession
物件的名稱】
前置條件:匯入隱式轉換並建立一個 RDD
- 通過手動確定轉換
-
通過反射確定(需要用到樣例類)
- 建立一個樣例類
case class People(name:String, age:Int) 複製程式碼
- 根據樣例類將
RDD
轉換為DataFrame
- 通過程式設計方式(瞭解)
- 匯入所需的型別
import org.apache.spark.sql.types._
複製程式碼
- 建立
Schema
val structType: StructType = StructType(StructField("name", StringType) :: StructField("age", IntegerType) :: Nil)
複製程式碼
- 匯入所需的型別
import org.apache.spark.sql.Row
複製程式碼
- 根據給定的型別建立二元組
RDD
val data = rdd.map{ x => val para = x.split(",");Row(para(0),para(1).trim.toInt)}
複製程式碼
- 根據資料及給定的
schema
建立DataFrame
val dataFrame = spark.createDataFrame(data, structType)
複製程式碼
5. DateFrame 轉換為 RDD
2.3 DataSet
DataSet
是具有強型別的資料集合,需要提供對應的型別資訊。
DataSet
的建立可以直接使用 Seq
靜態方法建立 或者 RDD
轉換 或者 DataFrame
轉換
1. 建立
- 建立一個樣例類
case class Person(name: String, age: Long)
複製程式碼
- 建立
DataSet
2. RDD 轉換為 DataSet
Spark SQL
能夠自動將包含有 case
類的 RDD
轉換成 DataFrame
,case
類定義了 table
的結構,case
類屬性通過反射變成了表的列名。case
類可以包含諸如 Seqs
或者 Array
等複雜的結構。
- 建立一個
RDD
- 建立一個樣例類
case class Person(name: String, age: Int)
複製程式碼
- 將
RDD
轉化為DataSet
3. DataSet 轉換為 RDD
2.4 DataFrame與DataSet的互操作
1. DataFrame 轉 Dataset
- 建立一個
DateFrame
- 建立一個樣例類並轉換
2. Dataset 轉 DataFrame
- 建立一個樣例類(同上)
- 建立
DataSet
val ds = Seq(Person("Andy", 32)).toDS()
複製程式碼
- 將
DataSet
轉化為DataFrame
val df = ds.toDF
複製程式碼
使用 as
方法,轉成 Dataset
,這在資料型別是 DataFrame
又需要針對各個欄位處理時極為方便。在使用一些特殊的操作時,一定要加上 import spark.implicits._
不然 toDF
、toDS
無法使用。
2.5 RDD,DataFrame,DataSet
在 Spark SQL
中 Spark
為我們提供了兩個新的抽象,分別是 DataFrame
和 DataSet
。他們和 RDD
有什麼區別呢?首先從版本的產生上來看:
RDD (Spark1.0) —> Dataframe(Spark1.3) —> Dataset(Spark1.6)
如果同樣的資料都給到這三個資料結構,他們分別計算之後,都會給出相同的結果。不同是的他們的執行效率和執行方式。在後期的 Spark
版本中,DataSet
有可能會逐步取代 RDD
和 DataFrame
成為唯一的 API
介面。
1. 三者的共性
(1)RDD
、DataFrame
、Dataset
全都是 spark
平臺下的分散式彈性資料集,為處理超大型資料提供便利;
(2)三者都有惰性機制,在進行建立、轉換,如 map
方法時,不會立即執行,只有在遇到 Action
如 foreach
時,三者才會開始遍歷運算;
(3)三者有許多共同的函式,如 filter
,排序
等;
(4)在對 DataFrame
和 Dataset
進行操作許多操作都需要這個包:import spark.implicits._
(在建立好 SparkSession
物件後儘量直接匯入)
這裡給出關於這三者講解比較深入的文章
2. 三者的轉換
2.6 IDEA 建立 Spark SQL 程式
通過一個簡單的案例快速入手如何在 IDEA
上開發 Spark SQL
程式
匯入以下依賴
<dependencies>
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-sql_2.11</artifactId>
<version>2.1.1</version>
</dependency>
</dependencies>
複製程式碼
程式碼實現
object Main2 {
def main(args: Array[String]): Unit = {
val session: SparkSession = SparkSession.builder().appName("spark sql").master("local[*]").getOrCreate()
import session.implicits._
val dataFrame: DataFrame = session.read.json("/home/cris/people.json")
//列印
dataFrame.show()
//DSL風格:查詢年齡在21歲以上的
dataFrame.filter($"age" > 21).show()
//建立臨時表
dataFrame.createOrReplaceTempView("persons")
//SQL風格:查詢年齡在21歲以上的
session.sql("SELECT * FROM persons where age > 21").show()
//關閉連線
session.stop()
}
}
複製程式碼
無法找到主類
如果在執行 Scala
或者是 java
程式中,報無法找到主類執行的異常,可能是專案的結構有問題,將父模組直接移除掉,然後重新匯入父模組即可
2.7 使用者自定義函式
1. 使用者自定義 UDF 函式
object MyFunc {
def main(args: Array[String]): Unit = {
val session: SparkSession = SparkSession.builder().appName("spark sql").master("local[*]").getOrCreate()
val dataFrame: DataFrame = session.read.json("/home/cris/people.json")
/*使用者自定義 UDF 函式*/
session.udf.register("addName", (x: String) => {
"cool:" + x
})
dataFrame.createOrReplaceTempView("people")
session.sql("select addName(name),age from people").show()
session.stop()
}
}
複製程式碼
結果如下
2. 使用者自定義 UDAF 函式
強型別的 Dataset
和弱型別的 DataFrame
都提供了相關的聚合函式, 如 count()
,countDistinct()
,avg()
,max()
,min()
。
除此之外,使用者可以設定自己的自定義聚合函式。通過繼承 UserDefinedAggregateFunction
來實現使用者自定義聚合函式
/**
* 定義自己的 UDAF 函式
*
* @author cris
* @version 1.0
**/
object MyFunc extends UserDefinedAggregateFunction {
// 聚合函式輸入引數的資料型別
override def inputSchema: StructType = StructType(StructField("inputField", LongType) :: Nil)
// 聚合緩衝區中值得資料型別
override def bufferSchema: StructType = {
StructType(StructField("sum", LongType) :: StructField("count", LongType) :: Nil)
}
// 返回值的資料型別
override def dataType: DataType = DoubleType
// 對於相同的輸入是否一直返回相同的輸出
override def deterministic: Boolean = true
// 初始化
override def initialize(buffer: MutableAggregationBuffer): Unit = {
// 工資的總額
buffer(0) = 0L
// 員工人數
buffer(1) = 0L
}
// 相同 Executor 間的資料合併
override def update(buffer: MutableAggregationBuffer, input: Row): Unit = {
buffer(0) = buffer.getLong(0) + input.getLong(0)
buffer(1) = buffer.getLong(1) + 1
}
// 不同 Executor 間的資料合併
override def merge(buffer1: MutableAggregationBuffer, buffer2: Row): Unit = {
buffer1(0) = buffer1.getLong(0) + buffer2.getLong(0)
buffer1(1) = buffer1.getLong(1) + buffer2.getLong(1)
}
// 最終函式計算的返回值
override def evaluate(buffer: Row): Double = {
buffer.getLong(0).toDouble / buffer.getLong(1)
}
}
複製程式碼
測試程式碼
object MyFuncTest2 {
def main(args: Array[String]): Unit = {
val session: SparkSession = SparkSession.builder().appName("spark sql").master("local[*]").getOrCreate()
val dataFrame: DataFrame = session.read.json("/home/cris/employees.json")
session.udf.register("avg", MyFunc)
dataFrame.createTempView("emp")
session.sql("select avg(salary) as avg_sal from emp").show()
session.stop()
}
}
複製程式碼
測試如下
三、Spark SQL 資料的載入與儲存
3.1 通用載入/儲存方法
1. 載入資料
- 通過
read
方法直接載入資料
scala> spark.read.
csv jdbc json orc parquet textFile… …
複製程式碼
注意:載入資料的相關引數需寫到上述方法中。如:textFile
需傳入載入資料的路徑,jdbc
需傳入 JDBC
相關引數
format
方法(瞭解)
scala> spark.read.format("…")[.option("…")].load("…")
複製程式碼
用法詳解:
(1)format("…"):指定載入的資料型別,包括"csv"、"jdbc"、"json"、"orc"、"parquet"和"textFile"。
(2)load("…"):在"csv"、"orc"、"parquet"和"textFile"格式下需要傳入載入資料的路徑。
(3)option("…"):在"jdbc"格式下需要傳入JDBC相應引數,url、user、password和dbtable
2. 儲存資料
write
直接儲存資料
scala> df.write.
csv jdbc json orc parquet textFile… …
複製程式碼
注意:儲存資料的相關引數需寫到上述方法中。如:textFile
需傳入載入資料的路徑,jdbc
需傳入 JDBC
相關引數
format
指定儲存資料型別(瞭解)
scala> df.write.format("…")[.option("…")].save("…")
複製程式碼
用法詳解:
(1)format("…"):指定儲存的資料型別,包括"csv"、"jdbc"、"json"、"orc"、"parquet"和"textFile"。
(2)save ("…"):在"csv"、"orc"、"parquet"和"textFile"格式下需要傳入儲存資料的路徑。
(3)option("…"):在"jdbc"格式下需要傳入JDBC相應引數,url、user、password和dbtable
3. 最佳示例程式碼
object Main2 {
def main(args: Array[String]): Unit = {
val session: SparkSession = SparkSession.builder().appName("spark sql").master("local[*]").getOrCreate()
val dataFrame: DataFrame = session.read.json("/home/cris/people.json")
//建立臨時表
dataFrame.createOrReplaceTempView("persons")
//SQL風格:查詢年齡在21歲以上的
val frame: DataFrame = session.sql("SELECT * FROM persons where age > 21")
frame.show()
frame.write.json("/home/cris/output")
//關閉連線
session.stop()
}
}
複製程式碼
執行效果
4. 檔案儲存選項
可以採用SaveMode
執行儲存操作,SaveMode
定義了對資料的處理模式。SaveMode
是一個列舉類,其中的常量包括:
(1)Append
:當儲存路徑或者表已存在時,追加內容;
(2)Overwrite
: 當儲存路徑或者表已存在時,覆寫內容;
(3)ErrorIfExists
:當儲存路徑或者表已存在時,報錯;
(4)Ignore
:當儲存路徑或者表已存在時,忽略當前的儲存操作
使用如下
df.write.mode(SaveMode.Append).save("… …")
複製程式碼
記得儲存選項放在 save
操作之前執行
5. 預設資料來源
Spark SQL
的預設資料來源為 Parquet
格式。資料來源為 Parquet
檔案時,Spark SQL
可以方便的執行所有的操作。修改配置項 spark.sql.sources.default
,可修改預設資料來源格式。
- 載入資料
val df = spark.read.load("./examples/src/main/resources/users.parquet")
複製程式碼
- 儲存資料
df.select("name", " color").write.save("user.parquet")
複製程式碼
3.2 JSON 檔案
Spark SQL
能夠自動推測 JSON
資料集的結構,並將它載入為一個 Dataset[Row]
. 可以通過 SparkSession.read.json()
去載入一個 一個 JSON
檔案。
注意:這個JSON檔案不是一個傳統的JSON檔案,每一行都得是一個JSON串。格式如下:
{"name":"Michael"}
{"name":"Andy", "age":30}
{"name":"Justin", "age":19}
複製程式碼
Spark-Shell
操作如下:
- 匯入隱式轉換
import spark.implicits._
複製程式碼
- 載入
JSON
檔案
val path = "examples/src/main/resources/people.json"
val peopleDF = spark.read.json(path)
複製程式碼
- 建立臨時表
peopleDF.createOrReplaceTempView("people")
複製程式碼
- 資料查詢
val teenagerNamesDF = spark.sql("SELECT name FROM people WHERE age BETWEEN 13 AND 19")
teenagerNamesDF.show()
+------+
| name|
+------+
|Justin|
+------+
複製程式碼
3.3 MySQL
Spark SQL
可以通過 JDBC
從關係型資料庫中讀取資料的方式建立 DataFrame
,通過對 DataFrame
一系列的計算後,還可以將資料再寫回關係型資料庫中。
可在啟動 shell
時指定相關的資料庫驅動路徑,或者將相關的資料庫驅動放到 Spark
的類路徑下(推薦)。
以 Spark-Shell 為例
- 啟動
Spark-Shell
[cris@hadoop101 spark-local]$ bin/spark-shell --master spark://hadoop101:7077 [--jars mysql-connector-java-5.1.27-bin.jar]
複製程式碼
建議將 MySQL
的驅動直接放入到 Spark
的類(jars
)路徑下,就不用每次進入 Spark-Shell
帶上 --jar
引數了
- 定義
JDBC
相關引數配置資訊
val connectionProperties = new Properties()
connectionProperties.put("user", "root")
connectionProperties.put("password", "000000")
複製程式碼
- 使用
read.jdbc
載入引數
val jdbcDF2 = spark.read.jdbc("jdbc:mysql://hadoop102:3306/spark", "person", connectionProperties)
複製程式碼
- 或者使用
format
形式載入配置引數(不推薦)
val jdbcDF = spark.read.format("jdbc").option("url", "jdbc:mysql://hadoop102:3306/spark").option("dbtable", " person").option("user", "root").option("password", "000000").load()
複製程式碼
- 使用
write.jdbc
儲存資料(可以使用檔案儲存選項)
jdbcDF2.write.mode(org.apache.spark.sql.SaveMode.Append).jdbc("jdbc:mysql://hadoop102:3306/spark", "person", connectionProperties)
複製程式碼
- 或者使用
format
形式儲存資料(不推薦)
jdbcDF.write
.format("jdbc")
.option("url", "jdbc:mysql://hadoop102:3306/spark")
.option("dbtable", "person")
.option("user", "root")
.option("password", "000000")
.save()
複製程式碼
以 IDEA 操作為例
pom.xml
匯入MySQL
驅動依賴
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
複製程式碼
MySQL
表資料
IDEA
操作程式碼如下
/**
* IDEA 測試 Spark SQL 連線遠端的 MySQL 獲取資料和寫入資料
*
* @author cris
* @version 1.0
**/
object MysqlTest {
def main(args: Array[String]): Unit = {
// 獲取 SparkSession
val session: SparkSession = SparkSession.builder().appName("spark sql").master("local[*]").getOrCreate()
// 設定配置引數
val properties = new Properties()
properties.put("user", "root")
properties.put("password", "000000")
// 從 MySQL 獲取資料,show() 方法實際呼叫的是 show(20),預設顯示 20 行資料
val dataFrame: DataFrame = session.read.jdbc("jdbc:mysql://hadoop102:3306/spark?characterEncoding=UTF-8", "person", properties)
dataFrame.show()
// 修改並儲存資料到 MySQL
dataFrame.write.mode(SaveMode.Append).jdbc("jdbc:mysql://hadoop102:3306/spark?characterEncoding=UTF-8", "person", properties)
session.stop()
}
}
複製程式碼
注意:防止中文亂碼,url
加上 ?characterEncoding=UTF-8
;寫入資料最好指定儲存模式 SaveMode
測試如下:
3.4 Hive
Apache Hive
是 Hadoop
上的 SQL
引擎,Spark SQL
編譯時可以包含 Hive
支援,也可以不包含。包含 Hive
支援的 Spark SQL
可以支援 Hive
表訪問、UDF
(使用者自定義函式)以及 Hive
查詢語言(HQL
)等。Spark-Shell
預設是Hive
支援的;程式碼中是預設不支援的,需要手動指定(加一個引數即可)。
內建 Hive (瞭解)
如果要使用內嵌的 Hive
,直接用就可以了。
- 簡單建立表
指定路徑下就會生成該表的資料夾
- 匯入檔案為表資料
在當前 Spark-local
路徑下,建立檔案 bb
1
2
3
4
5
複製程式碼
然後建立表,匯入資料
查詢也沒有問題
對應目錄下也生成了 bb
表的資料夾
外接 Hive(重要)
如果想連線外部已經部署好的 Hive
,需要通過以下幾個步驟:
- 將
Hive
中的hive-site.xml
拷貝或者軟連線到Spark
安裝目錄下的conf
目錄下
[cris@hadoop101 spark-local]$ cp /opt/module/hive-1.2.1/conf/hive-site.xml ./conf/
複製程式碼
- 將
JDBC
的驅動包放置在Spark
的.jars
目錄下,啟動Spark-Shell
[cris@hadoop101 spark-local]$ cp /opt/module/mysql-libs/mysql-connector-java-5.1.27/mysql-connector-java-5.1.27-bin.jar ./jars/
複製程式碼
可以通過 Hive
的客戶端建立一張表 users
hive> create table users(id int, name string) ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t';
複製程式碼
並匯入資料
hive> load data local inpath './user.txt' into users;
複製程式碼
此時 HDFS
顯示資料匯入成功
在 Spark-Shell
視窗檢視
執行 Hive
的查詢語句
可以在 Spark-Shell
執行所有的 Hive
語句,並且執行流程走的是 Spark
,而不是 MapReduce
執行Spark SQL CLI
Spark SQL CLI
可以很方便的在本地執行 Hive
後設資料服務以及從命令列執行查詢任務。在 Spark
目錄下執行如下命令啟動 Spark SQL CLI
,直接執行 SQL
語句,類似一個 Hive
視窗。
[cris@hadoop101 spark-local]$ bin/spark-sql
複製程式碼
如果使用這種模式進行測試,最好將 log4j
的日誌級別設定為 error
,否則會有很多 info
級別的日誌輸出
IDEA 測試 Spark 和 Hive 配合(重要)
首先 pom.xml
引入 Hive
依賴
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-hive_2.11</artifactId>
<version>2.1.1</version>
</dependency>
<dependency>
<groupId>org.apache.hive</groupId>
<artifactId>hive-exec</artifactId>
<version>1.2.1</version>
</dependency>
複製程式碼
然後將 Hive
的配置檔案 hive-site.xml
放入 resource
路徑下
hive-site.xml
<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<configuration>
<property>
<name>javax.jdo.option.ConnectionURL</name>
<value>jdbc:mysql://hadoop102:3306/metastore?createDatabaseIfNotExist=true</value>
<description>JDBC connect string for a JDBC metastore</description>
</property>
<property>
<name>javax.jdo.option.ConnectionDriverName</name>
<value>com.mysql.jdbc.Driver</value>
<description>Driver class name for a JDBC metastore</description>
</property>
<property>
<name>javax.jdo.option.ConnectionUserName</name>
<value>root</value>
<description>username to use against metastore database</description>
</property>
<property>
<name>javax.jdo.option.ConnectionPassword</name>
<value>000000</value>
<description>password to use against metastore database</description>
</property>
<property>
<name>hive.cli.print.header</name>
<value>true</value>
</property>
<property>
<name>hive.cli.print.current.db</name>
<value>true</value>
</property>
<property>
<name>hive.zookeeper.quorum</name>
<value>hadoop101,hadoop102,hadoop103</value>
<description>The list of ZooKeeper servers to talk to. This is only needed for read/write locks.</description>
</property>
<property>
<name>hive.zookeeper.client.port</name>
<value>2181</value>
<description>The port of ZooKeeper servers to talk to. This is only needed for read/write locks.</description>
</property>
</configuration>
複製程式碼
具體的配置介紹這裡不再贅述,可以參考我的 Hive 筆記
測試程式碼如下:
/**
* IDEA 測試 Spark SQL 和 Hive 的聯動
*
* @author cris
* @version 1.0
**/
object HiveTest {
def main(args: Array[String]): Unit = {
// 注意開啟 enableHiveSupport
val session: SparkSession = SparkSession.builder().enableHiveSupport().appName("spark sql").master("local[*]")
.getOrCreate()
session.sql("show tables").show()
// 注意關閉 session 連線
session.stop()
}
}
複製程式碼
執行結果如下
正好就是剛才建立的 Hive
表
IDEA 自動換行設定
Cris
的 IDEA
設定一行字數最多 120
,否則就自動換行,大大提高閱讀的舒適感和編碼的規範性
Deepin 的 Terminal 右鍵複製
因為 Cris
使用的是 Linux
桌面系統 Deepin
,所以經常使用自帶的 Terminal
連線遠端伺服器,這裡給出快速右鍵複製 Terminal
內容的設定
Typora 的快捷鍵自定義設定
因為 Cris
之前使用的是 MacBook
,輸入法搜狗會很智慧的為輸入的英文進行前後空格分割,換了 Deepin
後,自帶的雖然也是搜狗輸入法,但是沒有對英文自動空格分割的功能了,後面想想辦法,看怎麼解決~
因為要對英文和重要內容進行突出顯示,Typora
中設定 code
的快捷鍵預設為 Ctrl+Shift+`,比較麻煩,網上找了找自定義快捷鍵的設定,最後設定成 Ctrl+C