移轉指南:SQL、資料集和資料框架
- 從 Spark SQL 3.4 升級到 3.5
- 從 Spark SQL 3.3 升級到 3.4
- 從 Spark SQL 3.2 升級到 3.3
- 從 Spark SQL 3.1 升級到 3.2
- 從 Spark SQL 3.0 升級至 3.1
- 從 Spark SQL 3.0.1 升級至 3.0.2
- 從 Spark SQL 3.0 升級至 3.0.1
- 從 Spark SQL 2.4 升級至 3.0
- 從 Spark SQL 2.4.7 升級至 2.4.8
- 從 Spark SQL 2.4.5 升級至 2.4.6
- 從 Spark SQL 2.4.4 升級至 2.4.5
- 從 Spark SQL 2.4.3 升級至 2.4.4
- 從 Spark SQL 2.4 升級至 2.4.1
- 從 Spark SQL 2.3 升級至 2.4
- 從 Spark SQL 2.2 升級至 2.3
- 從 Spark SQL 2.1 升級至 2.2
- 從 Spark SQL 2.0 升級至 2.1
- 從 Spark SQL 1.6 升級至 2.0
- 從 Spark SQL 1.5 升級至 1.6
- 從 Spark SQL 1.4 升級至 1.5
- 從 Spark SQL 1.3 升級至 1.4
- 從 Spark SQL 1.0-1.2 升級至 1.3
- 與 Apache Hive 相容
從 Spark SQL 3.4 升級到 3.5
- 自 Spark 3.5 起,與 DS V2 推播相關的 JDBC 選項預設為
true
。這些選項包括:pushDownAggregate
、pushDownLimit
、pushDownOffset
和pushDownTableSample
。若要還原舊有行為,請將它們設定為false
。例如,將spark.sql.catalog.your_catalog_name.pushDownAggregate
設定為false
。 - 自 Spark 3.5 起,取消執行中的語法時,Spark thrift 伺服器會中斷任務。若要還原先前的行為,請將
spark.sql.thriftServer.interruptOnCancel
設定為false
。 - 自 Spark 3.5 起,Row 的 json 和 prettyJson 方法已移至
ToJsonUtil
。 - 自 Spark 3.5 起,
plan
欄位已從AnalysisException
移至EnhancedAnalysisException
。 - 自 Spark 3.5 起,
spark.sql.optimizer.canChangeCachedPlanOutputPartitioning
預設為啟用。若要還原先前的行為,請將spark.sql.optimizer.canChangeCachedPlanOutputPartitioning
設定為false
。 - 自 Spark 3.5 起,
array_insert
函數的負索引為 1 為基礎。它會在輸入陣列的結尾插入新的元素,索引為 -1。若要還原先前的行為,請將spark.sql.legacy.negativeIndexInArrayInsert
設定為true
。 - 自 Spark 3.5 起,當將 Interval 類型讀取為 Date 或 Timestamp 類型,或將 Decimal 類型讀取為較低精確度時,Avro 將會擲回
AnalysisException
。若要還原舊有行為,請將spark.sql.legacy.avro.allowIncompatibleSchema
設為true
從 Spark SQL 3.3 升級到 3.4
- 自 Spark 3.4 起,包含比目標表格更少欄位的明確欄位清單的 INSERT INTO 指令會自動為剩餘欄位加入對應的預設值(或對任何缺乏明確指定預設值的欄位加入 NULL)。在 Spark 3.3 或更早版本中,這些指令會失敗,並傳回錯誤報告,指出提供的欄位數目與目標表格中的欄位數目不符。請注意,停用
spark.sql.defaultColumn.useNullsForMissingDefaultValues
會還原先前的行為。 - 自 Spark 3.4 起,來自 Teradata 的 Number 或 Number(*) 將視為 Decimal(38,18)。在 Spark 3.3 或更早版本中,來自 Teradata 的 Number 或 Number(*) 將視為 Decimal(38, 0),這種情況下會移除小數部分。
- 自 Spark 3.4 起,v1 資料庫、表格、永久檢視和函數識別碼會包含「spark_catalog」作為目錄名稱(如果已定義資料庫),例如表格識別碼將會是:
spark_catalog.default.t
。若要還原舊有行為,請將spark.sql.legacy.v1IdentifierNoCatalog
設為true
。 - 自 Spark 3.4 起,當 ANSI SQL 模式(組態
spark.sql.ansi.enabled
)開啟時,Spark SQL 在取得具有不存在金鑰的地圖值時,總是會傳回 NULL 結果。在 Spark 3.3 或更早版本中,會出現錯誤。 - 自 Spark 3.4 起,SQL CLI
spark-sql
不會在AnalysisException
的錯誤訊息前印出前置詞Error in query:
。 - 自 Spark 3.4 起,當
regex
參數為空時,split
函數會忽略尾隨的空字串。 - 自 Spark 3.4 起,
to_binary
函數會對格式錯誤的str
輸入擲回錯誤。請使用try_to_binary
來容忍格式錯誤的輸入,並改傳回 NULL。- 有效的 Base64 字串應包含 base64 字母表中的符號(A-Za-z0-9+/)、選用填充(
=
)和選用空白。空白會在轉換中被略過,除非其前有填充符號。如果存在填充,則其應結束字串並遵循 RFC 4648 § 4 中所述的規則。 - 有效的十六進制字串應僅包含允許的符號 (0-9A-Fa-f)。
fmt
的有效值不區分大小寫,包括hex
、base64
、utf-8
、utf8
。
- 有效的 Base64 字串應包含 base64 字母表中的符號(A-Za-z0-9+/)、選用填充(
- 自 Spark 3.4 起,Spark 僅在建立分割區時,但其中一些分割區已存在時,才會擲回
PartitionsAlreadyExistException
。在 Spark 3.3 或更早版本中,Spark 可以擲回PartitionsAlreadyExistException
或PartitionAlreadyExistsException
。 - 自 Spark 3.4 起,Spark 會對 ALTER PARTITION 中的分割區規格進行驗證,以遵循
spark.sql.storeAssignmentPolicy
的行為,如果類型轉換失敗,可能會導致例外狀況,例如ALTER TABLE .. ADD PARTITION(p='a')
,如果欄位p
是 int 類型。若要還原舊有行為,請將spark.sql.legacy.skipTypeValidationOnAlterPartition
設為true
。 - 自 Spark 3.4 起,巢狀資料類型 (陣列、對應和結構) 預設啟用向量化讀取器。若要還原舊有行為,請將
spark.sql.orc.enableNestedColumnVectorizedReader
和spark.sql.parquet.enableNestedColumnVectorizedReader
設為false
。 - 自 Spark 3.4 起,CSV 資料來源不支援
BinaryType
。在 Spark 3.3 或更早版本中,使用者可以在 CSV 資料來源中寫入二進制欄位,但 CSV 檔案中的輸出內容是Object.toString()
,沒有意義;同時,如果使用者讀取含有二進制欄位的 CSV 表格,Spark 會擲回Unsupported type: binary
例外狀況。 - 自 Spark 3.4 起,預設啟用布隆過濾器聯結。若要還原舊有行為,請將
spark.sql.optimizer.runtime.bloomFilter.enabled
設為false
。
從 Spark SQL 3.2 升級到 3.3
-
自 Spark 3.3 起,Spark SQL 中的
histogram_numeric
函數會傳回結構陣列 (x, y) 的輸出類型,其中回傳值中「x」欄位的類型會從聚合函數中消耗的輸入值傳播。在 Spark 3.2 或更早版本中,「x」永遠是 double 類型。自 Spark 3.3 起,可以選擇使用設定檔spark.sql.legacy.histogramNumericPropagateInputType
還原為之前的行為。 -
自 Spark 3.3 起,Spark SQL 中的
DayTimeIntervalType
已對應到ArrowWriter
和ArrowColumnVector
開發人員 API 中的 ArrowDuration
類型。先前,DayTimeIntervalType
已對應到 ArrowInterval
類型,這與 Spark SQL 對應的其他語言類型不符。例如,DayTimeIntervalType
已對應到 Java 中的java.time.Duration
。 -
自 Spark 3.3 起,函數
lpad
和rpad
已重載,以支援位元組序列。當第一個引數是位元組序列時,選用的填充模式也必須是位元組序列,而結果是 BINARY 值。在此情況下,預設的填充模式為零位元組。若要回復永遠傳回字串類型的舊有行為,請將spark.sql.legacy.lpadRpadAlwaysReturnString
設為true
。 -
自 Spark 3.3 起,當使用 API
DataFrameReader.schema(schema: StructType).json(jsonDataset: Dataset[String])
和DataFrameReader.schema(schema: StructType).csv(csvDataset: Dataset[String])
指定架構,且該架構包含不可為 Null 的欄位時,Spark 會將不可為 Null 的架構轉換為可為 Null。若要回復尊重可為 Null 性的舊有行為,請將spark.sql.legacy.respectNullabilityInTextDatasetConversion
設為true
。 -
自 Spark 3.3 起,當未指定日期或時間戳記模式時,Spark 會使用
CAST
運算式方法將輸入字串轉換為日期/時間戳記。這些變更會影響 CSV/JSON 資料來源和剖析分割值。在 Spark 3.2 或更早版本中,當未設定日期或時間戳記模式時,Spark 會使用預設模式:日期為yyyy-MM-dd
,時間戳記為yyyy-MM-dd HH:mm:ss
。變更後,Spark 仍會辨識模式,以及日期模式
[+-]yyyy*
[+-]yyyy*-[m]m
[+-]yyyy*-[m]m-[d]d
[+-]yyyy*-[m]m-[d]d
[+-]yyyy*-[m]m-[d]d *
[+-]yyyy*-[m]m-[d]dT*
時間戳記模式
[+-]yyyy*
[+-]yyyy*-[m]m
[+-]yyyy*-[m]m-[d]d
[+-]yyyy*-[m]m-[d]d
[+-]yyyy*-[m]m-[d]d [h]h:[m]m:[s]s.[ms][ms][ms][us][us][us][zone_id]
[+-]yyyy*-[m]m-[d]dT[h]h:[m]m:[s]s.[ms][ms][ms][us][us][us][zone_id]
[h]h:[m]m:[s]s.[ms][ms][ms][us][us][us][zone_id]
T[h]h:[m]m:[s]s.[ms][ms][ms][us][us][us][zone_id]
-
從 Spark 3.3 開始,
format_string(strfmt, obj, ...)
和printf(strfmt, obj, ...)
中的strfmt
將不再支援使用「0$」指定第一個參數,在使用參數索引表示參數在參數清單中的位置時,第一個參數應始終以「1$」為參考。 -
從 Spark 3.3 開始,預設情況下,null 會寫入為 CSV 資料來源中的空字串。在 Spark 3.2 或更早版本中,null 會寫入為帶引號的空字串,
""
。若要還原先前的行為,請將nullValue
設定為""
,或將設定spark.sql.legacy.nullValueWrittenAsQuotedEmptyStringCsv
設定為true
。 -
從 Spark 3.3 開始,如果函數不存在,DESCRIBE FUNCTION 會失敗。在 Spark 3.2 或更早版本中,DESCRIBE FUNCTION 仍可執行並印出「Function: func_name not found」。
-
從 Spark 3.3 開始,表格屬性
external
成為保留字。如果您指定external
屬性,某些命令會失敗,例如CREATE TABLE ... TBLPROPERTIES
和ALTER TABLE ... SET TBLPROPERTIES
。在 Spark 3.2 及更早版本中,表格屬性external
會被自動忽略。您可以將spark.sql.legacy.notReserveProperties
設定為true
以還原舊的行為。 -
從 Spark 3.3 開始,如果函數名稱與內建函數的名稱相符且未限定,DROP FUNCTION 會失敗。在 Spark 3.2 或更早版本中,即使名稱未限定且與內建函數的名稱相同,DROP FUNCTION 仍可以刪除持續性函數。
-
從 Spark 3.3 開始,在從定義為
FloatType
或DoubleType
的 JSON 屬性讀取值時,字串"+Infinity"
、"+INF"
和"-INF"
現在會解析為適當的值,除了已支援的"Infinity"
和"-Infinity"
變異之外。此變更旨在提高與 Jackson 解析這些值的未加引號版本的一致性。此外,現在會遵循allowNonNumericNumbers
選項,因此如果停用此選項,這些字串現在會被視為無效。 -
自 Spark 3.3 起,Spark 會嘗試在
INSERT OVERWRITE DIRECTORY
中使用內建資料源寫入器,而不是 Hive serde。此行為僅在分別針對 Parquet 和 ORC 格式啟用spark.sql.hive.convertMetastoreParquet
或spark.sql.hive.convertMetastoreOrc
時才有效。若要還原 Spark 3.3 之前的行為,您可以將spark.sql.hive.convertMetastoreInsertDir
設為false
。 -
自 Spark 3.3 起,已修正類比函數的回傳類型精度。這可能會導致 Spark 在使用先前版本建立的檢視時,擲出
CANNOT_UP_CAST_DATATYPE
錯誤類別的AnalysisException
。在這種情況下,您需要使用較新的 Spark 版本,使用 ALTER VIEW AS 或 CREATE OR REPLACE VIEW AS 重新建立檢視。 -
自 Spark 3.3 起,
unbase64
函數會針對格式錯誤的str
輸入擲出錯誤。使用try_to_binary(<str>, 'base64')
來容許格式錯誤的輸入,並改為傳回 NULL。在 Spark 3.2 及更早版本中,unbase64
函數會針對格式錯誤的str
輸入傳回盡力而為的結果。 -
自 Spark 3.3.1 和 3.2.3 起,針對
SELECT ... GROUP BY a GROUPING SETS (b)
風格的 SQL 陳述式,grouping__id
會傳回與 Apache Spark 3.2.0、3.2.1、3.2.2 和 3.3.0 不同的值。它會根據使用者提供的群組依據運算式加上群組設定欄位來運算。若要還原 3.3.1 和 3.2.3 之前的行為,您可以設定spark.sql.legacy.groupingIdWithAppendedUserGroupBy
。詳細資訊請參閱 SPARK-40218 和 SPARK-40562。
從 Spark SQL 3.1 升級到 3.2
-
自 Spark 3.2 起,如果路徑包含空白,ADD FILE/JAR/ARCHIVE 指令需要每個路徑都以
"
或'
括起來。 -
自 Spark 3.2 起,所有支援的 JDBC 方言都對 ROWID 使用 StringType。在 Spark 3.1 或更早版本中,Oracle 方言使用 StringType,而其他方言使用 LongType。
-
在 Spark 3.2 中,PostgreSQL JDBC 方言對 MONEY 使用 StringType,且由於 PostgreSQL 的 JDBC 驅動程式無法正確處理這些類型,因此不支援 MONEY[]。在 Spark 3.1 或更早版本中,分別使用 DoubleType 和 DoubleType 的 ArrayType。
-
在 Spark 3.2 中,
spark.sql.adaptive.enabled
預設為啟用。若要還原 Spark 3.2 之前的行為,您可以將spark.sql.adaptive.enabled
設為false
。 - 在 Spark 3.2 中,下列元字元會在
show()
動作中被跳脫。在 Spark 3.1 或更早版本中,下列元字元會原樣輸出。\n
(換行)\r
(回車)\t
(水平標籤)\f
(換頁)\b
(退格)\u000B
(垂直標籤)\u0007
(鈴聲)
-
在 Spark 3.2 中,
ALTER TABLE .. RENAME TO PARTITION
會拋出PartitionAlreadyExistsException
,而不是AnalysisException
,這是針對目標分割區已存在的 Hive 外部表格。 -
在 Spark 3.2 中,腳本轉換預設的 FIELD DELIMIT 為
\u0001
,不使用 serde 模式,serde 屬性field.delim
為\t
,這是針對使用者指定 serde 時的 Hive serde 模式。在 Spark 3.1 或更早版本中,預設的 FIELD DELIMIT 為\t
,serde 屬性field.delim
為\u0001
,這是針對使用者指定 serde 時的 Hive serde 模式。 -
在 Spark 3.2 中,自動產生的
Cast
(例如由類型強制轉換規則新增的 Cast)會在產生欄位別名名稱時被移除。例如,sql("SELECT floor(1)").columns
會是FLOOR(1)
,而不是FLOOR(CAST(1 AS DOUBLE))
。 -
在 Spark 3.2 中,
SHOW TABLES
的輸出架構會變成namespace: string, tableName: string, isTemporary: boolean
。在 Spark 3.1 或更早版本中,namespace
欄位會命名為database
,這是針對內建目錄,而且 v2 目錄沒有isTemporary
欄位。若要使用內建目錄還原舊架構,您可以將spark.sql.legacy.keepCommandOutputSchema
設為true
。 -
在 Spark 3.2 中,
SHOW TABLE EXTENDED
的輸出架構會變成namespace: string, tableName: string, isTemporary: boolean, information: string
。在 Spark 3.1 或更早版本中,namespace
欄位會命名為database
,這是針對內建目錄,而且 v2 目錄沒有變更。若要使用內建目錄還原舊架構,您可以將spark.sql.legacy.keepCommandOutputSchema
設為true
。 -
在 Spark 3.2 中,
SHOW TBLPROPERTIES
的輸出架構會變成key: string, value: string
,無論您是否指定表屬性金鑰。在 Spark 3.1 及更早版本中,當您指定表屬性金鑰時,SHOW TBLPROPERTIES
的輸出架構是value: string
。若要使用內建目錄還原舊架構,您可以將spark.sql.legacy.keepCommandOutputSchema
設定為true
。 -
在 Spark 3.2 中,
DESCRIBE NAMESPACE
的輸出架構會變成info_name: string, info_value: string
。在 Spark 3.1 或更早版本中,info_name
欄位的名稱是database_description_item
,而info_value
欄位的名稱是database_description_value
(針對內建目錄)。若要使用內建目錄還原舊架構,您可以將spark.sql.legacy.keepCommandOutputSchema
設定為true
。 - 在 Spark 3.2 中,表格更新會清除表格的快取資料以及其所有相依項(例如檢視)的快取資料,同時保持相依項的快取狀態。下列命令會執行表格更新
ALTER TABLE .. ADD PARTITION
ALTER TABLE .. RENAME PARTITION
ALTER TABLE .. DROP PARTITION
ALTER TABLE .. RECOVER PARTITIONS
MSCK REPAIR TABLE
LOAD DATA
REFRESH TABLE
TRUNCATE TABLE
- 以及方法
spark.catalog.refreshTable
在 Spark 3.1 及更早版本中,表格更新會讓相依項保持非快取狀態。
-
在 Spark 3.2 中,
count(tblName.*)
的使用會遭到封鎖,以避免產生模稜兩可的結果。這是因為如果存在任何 Null 值,count(*)
和count(tblName.*)
的輸出結果會不同。若要還原 Spark 3.2 之前的行為,您可以將spark.sql.legacy.allowStarWithSingleTableIdentifierInCount
設定為true
。 -
在 Spark 3.2 中,我們支援 INSERT 和 ADD/DROP/RENAME PARTITION 的分割規格中的型別文字。例如,
ADD PARTITION(dt = date'2020-01-01')
會新增一個分割,其日期值為2020-01-01
。在 Spark 3.1 及更早版本中,分割值會以字串值date '2020-01-01'
進行剖析,這是一個不合法的日期值,而我們會在最後新增一個 Null 值分割。 -
在 Spark 3.2 中,
DataFrameNaFunctions.replace()
不再使用輸入欄位名稱的精確字串比對,以符合 SQL 語法並支援限定的欄位名稱。欄位名稱中包含句點(非巢狀)的輸入欄位名稱需要用反引號「`」來跳脫。現在,如果在資料框架結構中找不到欄位,它會擲回AnalysisException
。如果輸入欄位名稱是巢狀欄位,它也會擲回IllegalArgumentException
。在 Spark 3.1 及更早版本中,它會忽略無效的輸入欄位名稱和巢狀欄位名稱。 -
在 Spark 3.2 中,日期減法運算式,例如
date1 - date2
,會傳回DayTimeIntervalType
的值。在 Spark 3.1 及更早版本中,傳回的類型是CalendarIntervalType
。若要還原 Spark 3.2 之前的行為,您可以將spark.sql.legacy.interval.enabled
設定為true
。 -
在 Spark 3.2 中,時間戳記減法運算式,例如
timestamp '2021-03-31 23:48:00' - timestamp '2021-01-01 00:00:00'
,會傳回DayTimeIntervalType
的值。在 Spark 3.1 及更早版本中,相同運算式的類型是CalendarIntervalType
。若要還原 Spark 3.2 之前的行為,您可以將spark.sql.legacy.interval.enabled
設定為true
。 -
在 Spark 3.2 中,
CREATE TABLE .. LIKE ..
指令無法使用保留的屬性。您需要使用它們特定的子句來指定它們,例如CREATE TABLE test1 LIKE test LOCATION 'some path'
。您可以將spark.sql.legacy.notReserveProperties
設定為true
以忽略ParseException
,在此情況下,這些屬性將會被靜默移除,例如:TBLPROPERTIES('owner'='yao')
將不會有任何作用。在 Spark 3.1 及更早版本中,保留的屬性可以在CREATE TABLE .. LIKE ..
指令中使用,但沒有副作用,例如TBLPROPERTIES('location'='/tmp')
不會變更表格的位置,而只會建立一個沒有主體的屬性,就像'a'='b'
。 -
在 Spark 3.2 中,
TRANSFORM
算子不支援輸入中的別名。在 Spark 3.1 及更早版本中,我們可以撰寫腳本轉換,例如SELECT TRANSFORM(a AS c1, b AS c2) USING 'cat' FROM TBL
。 -
在 Spark 3.2 中,
TRANSFORM
算子可以在沒有 Hive SerDe 的情況下支援ArrayType/MapType/StructType
,在此模式中,我們使用StructsToJson
將ArrayType/MapType/StructType
欄位轉換為STRING
,並使用JsonToStructs
將STRING
解析為ArrayType/MapType/StructType
。在 Spark 3.1 中,Spark 僅支援將ArrayType/MapType/StructType
欄位作為STRING
的情況,但無法支援將STRING
解析為ArrayType/MapType/StructType
輸出欄位。 -
在 Spark 3.2 中,單位到單位的區間文字,例如
INTERVAL '1-1' YEAR TO MONTH
和單位清單區間文字,例如INTERVAL '3' DAYS '1' HOUR
會轉換成 ANSI 區間類型:YearMonthIntervalType
或DayTimeIntervalType
。在 Spark 3.1 及更早版本中,此類區間文字會轉換成CalendarIntervalType
。若要還原 Spark 3.2 之前的行為,您可以將spark.sql.legacy.interval.enabled
設為true
。 -
在 Spark 3.2 中,單位清單區間文字無法混合年-月欄位 (YEAR 和 MONTH) 和日-時欄位 (WEEK、DAY、…、MICROSECOND)。例如,
INTERVAL 1 month 1 hour
在 Spark 3.2 中無效。在 Spark 3.1 及更早版本中,沒有此類限制,且文字會傳回CalendarIntervalType
的值。若要還原 Spark 3.2 之前的行為,您可以將spark.sql.legacy.interval.enabled
設為true
。 -
在 Spark 3.2 中,Spark 支援
DayTimeIntervalType
和YearMonthIntervalType
作為 HiveSERDE
模式中TRANSFORM
子句的輸入和輸出,當這兩種類型用作輸入時,HiveSERDE
模式和ROW FORMAT DELIMITED
模式之間的行為不同。在 HiveSERDE
模式中,DayTimeIntervalType
欄位會轉換成HiveIntervalDayTime
,其字串格式為[-]?d h:m:s.n
,但在ROW FORMAT DELIMITED
模式中,格式為INTERVAL '[-]?d h:m:s.n' DAY TO TIME
。在 HiveSERDE
模式中,YearMonthIntervalType
欄位會轉換成HiveIntervalYearMonth
,其字串格式為[-]?y-m
,但在ROW FORMAT DELIMITED
模式中,格式為INTERVAL '[-]?y-m' YEAR TO MONTH
。 -
在 Spark 3.2 中,浮點類型會產生
hash(0) == hash(-0)
。先前會產生不同的值。 -
在 Spark 3.2 中,
CREATE TABLE AS SELECT
具有非空LOCATION
會擲回AnalysisException
。若要還原 Spark 3.2 之前的行為,您可以將spark.sql.legacy.allowNonEmptyLocationInCTAS
設為true
。 -
在 Spark 3.2 中,特殊日期時間值(例如
epoch
、today
、yesterday
、tomorrow
和now
)僅在類型化文字或可折疊字串的強制轉換中受支援,例如select timestamp'now'
或select cast('today' as date)
。在 Spark 3.1 和 3.0 中,此類特殊值在任何將字串強制轉換為日期/時間戳記時都受支援。若要在 Spark 3.1 和 3.0 中將這些特殊值保留為日期/時間戳記,您應該手動取代它們,例如if (c in ('now', 'today'), current_date(), cast(c as date))
。 -
在 Spark 3.2 中,
FloatType
會對應到 MySQL 中的FLOAT
。在此之前,它會對應到REAL
,而REAL
在 MySQL 中預設是DOUBLE PRECISION
的同義詞。 -
在 Spark 3.2 中,
DataFrameWriter
觸發的查詢執行在傳送到QueryExecutionListener
時,其名稱永遠是command
。在 Spark 3.1 及更早版本中,名稱為save
、insertInto
、saveAsTable
之一。 -
在 Spark 3.2 中,
Dataset.unionByName
將allowMissingColumns
設為 true,會將遺失的巢狀欄位新增到結構的尾端。在 Spark 3.1 中,巢狀結構欄位會依字母順序排序。 -
在 Spark 3.2 中,如果輸入查詢輸出欄位包含自動產生的別名,則建立/變更檢視會失敗。這是為了確保查詢輸出欄位名稱在不同的 Spark 版本中保持穩定。若要還原 Spark 3.2 之前的行為,請將
spark.sql.legacy.allowAutoGeneratedAliasForView
設為true
。 - 在 Spark 3.2 中,日期 +/- 僅包含日時間欄位的間隔,例如
date '2011-11-11' + interval 12 hours
會傳回時間戳記。在 Spark 3.1 及更早版本中,相同的表達式會傳回日期。若要還原 Spark 3.2 之前的行為,您可以使用cast
將時間戳記轉換為日期。
從 Spark SQL 3.0 升級至 3.1
-
在 Spark 3.1 中,統計聚合函數包括
std
、stddev
、stddev_samp
、variance
、var_samp
、skewness
、kurtosis
、covar_samp
、corr
會傳回NULL
,而不是Double.NaN
,這是因為在表達式評估期間發生DivideByZero
,例如,當stddev_samp
套用於單一元素集合時。在 Spark 3.0 及更早版本中,它會在這種情況下傳回Double.NaN
。若要還原 Spark 3.1 之前的行為,您可以將spark.sql.legacy.statisticalAggregate
設為true
。 -
在 Spark 3.1 中,grouping_id() 會傳回長整數值。在 Spark 3.0 及更早版本中,此函數會傳回整數值。若要還原 Spark 3.1 之前的行為,您可以將
spark.sql.legacy.integerGroupingId
設為true
。 -
在 Spark 3.1 中,SQL UI 資料採用
formatted
模式來解釋查詢計畫的結果。若要還原 Spark 3.1 之前的行為,您可以將spark.sql.ui.explainMode
設為extended
。 -
在 Spark 3.1 中,如果指定的日期時間模式無效,
from_unixtime
、unix_timestamp
、to_unix_timestamp
、to_timestamp
和to_date
將會失敗。在 Spark 3.0 或更早版本中,它們會產生NULL
。 -
在 Spark 3.1 中,如果 Parquet、ORC、Avro 和 JSON 資料來源在頂層欄位和巢狀結構中偵測到重複名稱,它們會在讀取時拋出例外狀況
org.apache.spark.sql.AnalysisException: Found duplicate column(s) in the data schema
。這些資料來源會在偵測欄位名稱重複時考量 SQL 設定spark.sql.caseSensitive
。 -
在 Spark 3.1 中,結構和對應在轉換成字串時會加上
{}
括號。例如,show()
動作和CAST
表達式會使用此類括號。在 Spark 3.0 和更早版本中,[]
括號用於相同目的。若要還原 Spark 3.1 之前的行為,您可以將spark.sql.legacy.castComplexTypesToString.enabled
設為true
。 -
在 Spark 3.1 中,結構、陣列和對應的 NULL 元素在轉換成字串時會轉換為「null」。在 Spark 3.0 或更早版本中,NULL 元素會轉換為空字串。若要還原 Spark 3.1 之前的行為,您可以將
spark.sql.legacy.castComplexTypesToString.enabled
設為true
。 -
在 Spark 3.1 中,當
spark.sql.ansi.enabled
為 false 時,如果十進位類型欄位的總和溢位,Spark 始終會傳回 null。在 Spark 3.0 或更早版本中,這種情況下,十進位類型欄位的總和可能會傳回 null 或不正確的結果,甚至在執行階段失敗(視實際查詢計畫執行而定)。 -
在 Spark 3.1 中,當使用路徑參數呼叫下列方法時,
path
選項無法共存:DataFrameReader.load()
、DataFrameWriter.save()
、DataStreamReader.load()
或DataStreamWriter.start()
。此外,paths
選項無法與DataFrameReader.load()
共存。例如,spark.read.format("csv").option("path", "/tmp").load("/tmp2")
或spark.read.option("path", "/tmp").csv("/tmp2")
會拋出org.apache.spark.sql.AnalysisException
。在 Spark 3.0 和以下版本中,如果將一個路徑參數傳遞給上述方法,path
選項會被覆寫;如果將多個路徑參數傳遞給DataFrameReader.load()
,path
選項會新增到整體路徑中。若要還原 Spark 3.1 之前的行為,您可以將spark.sql.legacy.pathOptionBehavior.enabled
設為true
。 -
在 Spark 3.1 中,對於不完整的區間文字(例如
INTERVAL '1'
、INTERVAL '1 DAY 2'
),會傳回IllegalArgumentException
,這些文字無效。在 Spark 3.0 中,這些文字會產生NULL
。 -
在 Spark 3.1 中,我們移除了內建的 Hive 1.2。您需要將自訂 SerDes 移轉到 Hive 2.3。請參閱 HIVE-15167 以取得更多詳細資訊。
-
在 Spark 3.1 中,如果時間戳早於 1900-01-01 00:00:00Z,並且載入(儲存)為 INT96 類型,則從/到 Parquet 檔案載入和儲存時間戳會失敗。在 Spark 3.0 中,這些動作不會失敗,但可能會因為從儒略曆重新設定為前儒略曆或相反,而導致輸入時間戳轉移。若要還原 Spark 3.1 之前的行為,你可以將
spark.sql.legacy.parquet.int96RebaseModeInRead
或/和spark.sql.legacy.parquet.int96RebaseModeInWrite
設定為LEGACY
。 -
在 Spark 3.1 中,
schema_of_json
和schema_of_csv
函數會以 SQL 格式傳回架構,其中欄位名稱有引號。在 Spark 3.0 中,函數會傳回沒有欄位引號且為小寫的目錄字串。 -
在 Spark 3.1 中,更新資料表會觸發所有其他參考該資料表的快取的快取解除作業,即使資料表本身沒有快取。在 Spark 3.0 中,只有在資料表本身有快取時,才會觸發該作業。
-
在 Spark 3.1 中,建立或變更永久檢視會擷取執行時期 SQL 設定,並將其儲存為檢視屬性。這些設定會在檢視解析的剖析和分析階段套用。若要還原 Spark 3.1 之前的行為,你可以將
spark.sql.legacy.useCurrentConfigsForView
設定為true
。 -
在 Spark 3.1 中,暫時檢視會與永久檢視有相同的行為,即擷取並儲存執行時期 SQL 設定、SQL 文字、目錄和名稱空間。擷取的檢視屬性會在檢視解析的剖析和分析階段套用。若要還原 Spark 3.1 之前的行為,你可以將
spark.sql.legacy.storeAnalyzedPlanForView
設定為true
。 -
在 Spark 3.1 中,透過
CACHE TABLE ... AS SELECT
建立的暫時檢視也會與永久檢視有相同的行為。特別是,當暫時檢視被刪除時,Spark 會使所有其快取依賴項無效,以及暫時檢視本身的快取。這與 Spark 3.0 及以下版本不同,後者只會執行後者。若要還原之前的行為,你可以將spark.sql.legacy.storeAnalyzedPlanForView
設定為true
。 -
自 Spark 3.1 起,資料表架構中支援 CHAR/CHARACTER 和 VARCHAR 類型。資料表掃描/插入會遵循 char/varchar 語意。如果 char/varchar 用於資料表架構以外的地方,則會擲回例外(CAST 是例外,它只會將 char/varchar 視為字串,就像以前一樣)。若要還原 Spark 3.1 之前的行為,它將它們視為 STRING 類型並忽略長度參數,例如
CHAR(4)
,你可以將spark.sql.legacy.charVarcharAsString
設定為true
。 -
在 Spark 3.1 中,
AnalysisException
已被其子類別取代,這些子類別會在以下情況下針對來自 Hive 外部目錄的表格擲出ALTER TABLE .. ADD PARTITION
如果新分區已存在,則會擲出PartitionsAlreadyExistException
ALTER TABLE .. DROP PARTITION
如果分區不存在,則會擲出NoSuchPartitionsException
從 Spark SQL 3.0.1 升級至 3.0.2
- 在 Spark 3.0.2 中,
AnalysisException
已被其子類別取代,這些子類別會在以下情況下針對來自 Hive 外部目錄的表格擲出ALTER TABLE .. ADD PARTITION
如果新分區已存在,則會擲出PartitionsAlreadyExistException
ALTER TABLE .. DROP PARTITION
如果分區不存在,則會擲出NoSuchPartitionsException
-
在 Spark 3.0.2 中,
PARTITION(col=null)
在分區規格中總是會被解析為 null 文字。在 Spark 3.0.1 或更早版本中,如果分區欄位是字串類型,則會將其解析為其文字表示的字串文字,例如字串「null」。若要還原舊有行為,您可以將spark.sql.legacy.parseNullPartitionSpecAsStringLiteral
設定為 true。 - 在 Spark 3.0.2 中,
SHOW DATABASES
的輸出架構變為namespace: string
。在 Spark 版本 3.0.1 及更早版本中,架構為databaseName: string
。自 Spark 3.0.2 起,您可以透過將spark.sql.legacy.keepCommandOutputSchema
設定為true
來還原舊有架構。
從 Spark SQL 3.0 升級至 3.0.1
-
在 Spark 3.0 中,如果 JSON 資料來源和 JSON 函數
schema_of_json
的字串值符合 JSON 選項timestampFormat
定義的模式,則會推論出 TimestampType。自版本 3.0.1 起,預設會停用時間戳記類型推論。將 JSON 選項inferTimestamp
設定為true
以啟用此類型的推論。 -
在 Spark 3.0 中,將字串轉換為整數類型(tinyint、smallint、int 和 bigint)、日期時間類型(date、timestamp 和 interval)和布林類型時,將會修剪開頭和結尾字元(<= ASCII 32)。例如,
cast('\b1\b' as int)
會產生1
。自 Spark 3.0.1 起,只會修剪開頭和結尾的空白 ASCII 字元。例如,cast('\t1\t' as int)
會產生1
,但cast('\b1\b' as int)
會產生NULL
。
從 Spark SQL 2.4 升級至 3.0
Dataset/DataFrame API
-
在 Spark 3.0 中,Dataset 和 DataFrame API
unionAll
不再標示為已棄用。它是union
的別名。 -
在 Spark 2.4 及以下版本中,如果鍵是非結構類型(例如 int、字串、陣列等),
Dataset.groupByKey
會產生一個群組化資料集,其鍵屬性的名稱錯誤地命名為「value」。這違反直覺,而且會讓聚合查詢的結構難以預期。例如,ds.groupByKey(...).count()
的結構是(value, count)
。自 Spark 3.0 起,我們將群組屬性命名為「key」。舊行為會保留在新增加的設定檔spark.sql.legacy.dataset.nameNonStructGroupingKeyAsValue
中,其預設值為false
。 -
在 Spark 3.0 中,欄位元資料將永遠在 API
Column.name
和Column.as
中傳播。在 Spark 2.4 及更早版本中,NamedExpression
的元資料會設定為呼叫 API 時新欄位的explicitMetadata
,即使基礎NamedExpression
變更元資料,它也不會變更。若要還原 Spark 3.0 之前的行為,您可以使用具有明確元資料的 APIas(alias: String, metadata: Metadata)
。 -
將資料集轉換為另一個資料集時,Spark 會將原始資料集中的欄位向上轉換為目標資料集中的對應欄位類型。在 2.4 及更早版本中,此向上轉換並非非常嚴格,例如
Seq("str").toDS.as[Int]
會失敗,但Seq("str").toDS.as[Boolean]
會運作,並在執行期間擲出 NPE。在 Spark 3.0 中,向上轉換更嚴格,且不允許將字串轉換為其他類型,也就是說Seq("str").toDS.as[Boolean]
會在分析期間失敗。若要回復 Spark 3.0 之前的行為,請將spark.sql.legacy.doLooseUpcast
設為true
。
DDL 語法
-
在 Spark 3.0 中,將值插入資料表欄位時,資料類型不同,類型強制轉換會根據 ANSI SQL 標準執行。某些不合理的類型轉換,例如將
字串
轉換為整數
,以及將雙精度
轉換為布林
,是不被允許的。如果值超出欄位資料類型的範圍,會擲出執行時期例外。在 Spark 2.4 及更早版本中,只要是有效的Cast
,資料表插入期間的類型轉換都是允許的。將超出範圍的值插入到整數欄位時,會插入值的低階位元 (與 Java/Scala 數值類型轉換相同)。例如,如果將 257 插入到位元組類型欄位,結果會是 1。此行為由選項spark.sql.storeAssignmentPolicy
控制,預設值為「ANSI」。將選項設為「Legacy」會回復之前的行為。 -
先前
ADD JAR
命令會傳回包含單一值 0 的結果集。現在會傳回一個空的結果集。 -
Spark 2.4 及更早版本:即使指定的 key 是針對
SparkConf
項目,且沒有任何作用,SET
命令也會在沒有任何警告的情況下運作,因為該命令不會更新SparkConf
,但此行為可能會讓使用者感到困惑。在 3.0 中,如果使用SparkConf
key,命令會失敗。您可以透過將spark.sql.legacy.setCommandRejectsSparkCoreConfs
設為false
來停用此類檢查。 -
重新整理快取表格會觸發表格取消快取操作,然後(延遲)執行表格快取操作。在 Spark 版本 2.4 及以下版本中,快取名稱和儲存層級在取消快取操作之前並未保留。因此,快取名稱和儲存層級可能會意外變更。在 Spark 3.0 中,快取名稱和儲存層級會先保留以進行快取重新建立。這有助於在表格重新整理時維持一致的快取行為。
-
在 Spark 3.0 中,下列清單中的屬性會保留;如果您在
CREATE DATABASE ... WITH DBPROPERTIES
和ALTER TABLE ... SET TBLPROPERTIES
等位置指定保留屬性,指令會失敗。您需要其特定子句才能指定它們,例如CREATE DATABASE test COMMENT 'any comment' LOCATION 'some path'
。您可以將spark.sql.legacy.notReserveProperties
設為true
以忽略ParseException
,在此情況下,這些屬性會在不通知您的情況下移除,例如:SET DBPROPERTIES('location'='/tmp')
沒有任何作用。在 Spark 版本 2.4 及以下版本中,這些屬性既未保留,也沒有副作用,例如SET DBPROPERTIES('location'='/tmp')
沒有變更資料庫的位置,只會建立一個無標題屬性,就像'a'='b'
一樣。屬性(大小寫敏感) 資料庫保留 表格保留 備註 provider 否 是 對於表格,請使用 USING
子句來指定它。一旦設定,便無法變更。location 是 是 對於資料庫和表格,請使用 LOCATION
子句來指定它。owner 是 是 對於資料庫和表格,由執行 spark 並建立表格的使用者決定。 -
在 Spark 3.0 中,您可以使用
ADD FILE
來新增檔案目錄。較早之前,您只能使用此命令新增單一檔案。若要回復到較早版本的行為,請將spark.sql.legacy.addSingleFileInAddFile
設定為true
。 -
在 Spark 3.0 中,如果表格不存在,
SHOW TBLPROPERTIES
會擲回AnalysisException
。在 Spark 版本 2.4 及以下版本中,此情境會導致NoSuchTableException
。 -
在 Spark 3.0 中,
SHOW CREATE TABLE table_identifier
始終會傳回 Spark DDL,即使給定的表格是 Hive SerDe 表格。若要產生 Hive DDL,請改用SHOW CREATE TABLE table_identifier AS SERDE
命令。 -
在 Spark 3.0 中,非 Hive-Serde 表格中不允許 CHAR 類型的欄位,如果偵測到 CHAR 類型,CREATE/ALTER TABLE 命令會失敗。請改用 STRING 類型。在 Spark 版本 2.4 及以下版本中,CHAR 類型會被視為 STRING 類型,而長度參數會被忽略。
UDF 及內建函數
-
在 Spark 3.0 中,
date_add
和date_sub
函數只接受 int、smallint、tinyint 作為第二個引數;小數和非字串文字不再有效,例如:date_add(cast('1964-05-23' as date), '12.34')
會導致AnalysisException
。請注意,字串文字仍然允許,但如果字串內容不是有效的整數,Spark 會擲回AnalysisException
。在 Spark 版本 2.4 及以下版本中,如果第二個引數是小數或字串值,它會被強制轉換為 int 值,而結果是1964-06-04
的日期值。 -
在 Spark 3.0 中,函數
percentile_approx
及其別名approx_percentile
只接受範圍在[1, 2147483647]
中的整數值作為其第三個引數accuracy
,小數和字串類型不允許,例如,percentile_approx(10.0, 0.2, 1.8D)
會導致AnalysisException
。在 Spark 版本 2.4 及以下版本中,如果accuracy
是小數或字串值,它會被強制轉換為 int 值,percentile_approx(10.0, 0.2, 1.8D)
會被操作為percentile_approx(10.0, 0.2, 1)
,結果為10.0
。 -
在 Spark 3.0 中,當對
MapType
元素套用雜湊表達式時,會擲回分析例外。若要還原 Spark 3.0 之前的行為,請將spark.sql.legacy.allowHashOnMapType
設為true
。 -
在 Spark 3.0 中,當
array
/map
函數在沒有任何參數的情況下呼叫時,它會傳回一個空集合,其中NullType
為元素類型。在 Spark 2.4 及以下版本中,它會傳回一個空集合,其中StringType
為元素類型。若要還原 Spark 3.0 之前的行為,您可以將spark.sql.legacy.createEmptyCollectionUsingStringType
設為true
。 -
在 Spark 3.0 中,
from_json
函數支援兩種模式 -PERMISSIVE
和FAILFAST
。模式可透過mode
選項設定。預設模式已變更為PERMISSIVE
。在先前版本中,from_json
的行為既不符合PERMISSIVE
也不符合FAILFAST
,特別是在處理格式錯誤的 JSON 記錄時。例如,JSON 字串{"a" 1}
搭配架構a INT
,會在先前版本中轉換為null
,但 Spark 3.0 會將其轉換為Row(null)
。 -
在 Spark 2.4 及以下版本中,您可以透過內建函數(例如
CreateMap
、MapFromArrays
等)建立具有映射類型金鑰的映射值。在 Spark 3.0 中,不允許使用這些內建函數建立具有映射類型金鑰的映射值。使用者可以使用map_entries
函數將映射轉換為 array<struct<key, value» 作為解決方法。此外,使用者仍可以從資料來源或 Java/Scala 集合讀取具有映射類型金鑰的映射值,儘管不建議這麼做。 -
在 Spark 2.4 及以下版本中,您可以透過內建函數建立具有重複金鑰的映射,例如
CreateMap
、StringToMap
等。具有重複金鑰的映射行為未定義,例如,映射查詢會尊重最先出現的重複金鑰,Dataset.collect
僅保留最後出現的重複金鑰,MapKeys
會傳回重複金鑰等。在 Spark 3.0 中,當找到重複金鑰時,Spark 會擲出RuntimeException
。您可以將spark.sql.mapKeyDedupPolicy
設定為LAST_WIN
,以使用最後獲勝原則來重複刪除映射金鑰。使用者仍可以從未強制執行的資料來源(例如 Parquet)讀取具有重複金鑰的映射值,此行為未定義。 -
在 Spark 3.0 中,預設不允許使用
org.apache.spark.sql.functions.udf(AnyRef, DataType)
。建議移除傳回類型參數以自動切換至已輸入 Scala udf,或將spark.sql.legacy.allowUntypedScalaUDF
設定為 true 以繼續使用它。在 Spark 2.4 及以下版本中,如果org.apache.spark.sql.functions.udf(AnyRef, DataType)
取得具有基本類型參數的 Scala 閉包,則在輸入值為 null 時,傳回的 UDF 會傳回 null。然而,在 Spark 3.0 中,如果輸入值為 null,則 UDF 會傳回 Java 類型的預設值。例如,val f = udf((x: Int) => x, IntegerType)
,如果欄位x
為 null,則f($"x")
會在 Spark 2.4 及以下版本中傳回 null,並在 Spark 3.0 中傳回 0。此行為變更的引入是因為 Spark 3.0 預設使用 Scala 2.12 建置。 -
在 Spark 3.0 中,高階函數
exists
遵循三值布林邏輯,也就是說,如果predicate
傳回任何null
且未取得任何true
,則exists
會傳回null
,而非false
。例如,exists(array(1, null, 3), x -> x % 2 == 0)
為null
。可以透過將spark.sql.legacy.followThreeValuedLogicInArrayExists
設定為false
來回復先前的行為。 -
在 Spark 3.0 中,如果原始日期是某個月的最後一天,
add_months
函數不會將結果日期調整為該月的最後一天。例如,select add_months(DATE'2019-02-28', 1)
的結果為2019-03-28
。在 Spark 2.4 及更早版本中,如果原始日期是某個月的最後一天,則會調整結果日期。例如,將一個月加到2019-02-28
會得到2019-03-31
。 -
在 Spark 2.4 及更早版本中,
current_timestamp
函數僅傳回具有毫秒解析度的時間戳記。在 Spark 3.0 中,如果系統上可用的基礎時鐘提供此類解析度,則此函數可以傳回具有微秒解析度的結果。 -
在 Spark 3.0 中,0 個參數的 Java UDF 在執行器端執行的方式與其他 UDF 相同。在 Spark 2.4 及更早版本中,僅 0 個參數的 Java UDF 在驅動程式端執行,並且結果會傳播到執行器,這在某些情況下可能效能較佳,但在某些情況下會導致正確性問題的不一致。
-
在不同平台上,
java.lang.Math
的log
、log1p
、exp
、expm1
和pow
的結果可能有所不同。在 Spark 3.0 中,等效 SQL 函數(包括LOG10
等相關 SQL 函數)的結果與java.lang.StrictMath
一致。在幾乎所有情況下,這對傳回值沒有影響,而且差異非常小,但可能無法在 x86 平台上與java.lang.Math
完全匹配,例如log(3.0)
,其值在Math.log()
和StrictMath.log()
之間有所不同。 -
在 Spark 3.0 中,當將字串文字(例如「Infinity」、「+Infinity」、「-Infinity」、「NaN」、「Inf」、「+Inf」、「-Inf」)轉換為
Double
或Float
類型時,cast
函數會以不區分大小寫的方式處理這些字串文字,以確保與其他資料庫系統有更好的相容性。此行為變更在下表中說明操作 Spark 3.0 之前的結果 Spark 3.0 中的結果 CAST(‘infinity’ AS DOUBLE) NULL Double.PositiveInfinity CAST(‘+infinity’ AS DOUBLE) NULL Double.PositiveInfinity CAST(‘inf’ AS DOUBLE) NULL Double.PositiveInfinity CAST(‘inf’ AS DOUBLE) NULL Double.PositiveInfinity CAST(‘-infinity’ AS DOUBLE) NULL Double.NegativeInfinity CAST(‘-inf’ AS DOUBLE) NULL Double.NegativeInfinity CAST(‘infinity’ AS FLOAT) NULL Float.PositiveInfinity CAST(‘+infinity’ AS FLOAT) NULL Float.PositiveInfinity CAST(‘inf’ AS FLOAT) NULL Float.PositiveInfinity CAST(‘+inf’ AS FLOAT) NULL Float.PositiveInfinity CAST(‘-infinity’ AS FLOAT) NULL Float.NegativeInfinity CAST(‘-inf’ AS FLOAT) NULL Float.NegativeInfinity CAST(‘nan’ AS DOUBLE) NULL Double.NaN CAST(‘nan’ AS FLOAT) NULL Float.NaN -
在 Spark 3.0 中,將區間值轉換為字串類型時,沒有「區間」前綴,例如
1 days 2 hours
。在 Spark 2.4 及以下版本中,字串包含「區間」前綴,例如interval 1 days 2 hours
。 -
在 Spark 3.0 中,將字串值轉換為整數類型 (tinyint、smallint、int 和 bigint)、日期時間類型 (date、timestamp 和 interval) 和布林類型時,會在轉換為這些類型值之前修剪前導和尾隨空白 (<= ASCII 32),例如,
cast(' 1\t' as int)
結果為1
,cast(' 1\t' as boolean)
結果為true
,cast('2019-10-10\t as date)
結果為日期值2019-10-10
。在 Spark 2.4 及以下版本中,將字串轉換為整數和布林值時,不會修剪兩端的空白;上述結果為null
,而對於日期時間,只會移除尾隨空白 (= ASCII 32)。
查詢引擎
-
在 Spark 2.4 及以下版本中,意外支援
FROM <table>
或FROM <table> UNION ALL FROM <table>
等 SQL 查詢。在 hive 風格的FROM <table> SELECT <expr>
中,SELECT
子句不可忽略。Hive 和 Presto 都不支援此語法。在 Spark 3.0 中,這些查詢會被視為無效。 -
在 Spark 3.0 中,區間文字語法不再允許多個 from-to 單位。例如,
SELECT INTERVAL '1-1' YEAR TO MONTH '2-2' YEAR TO MONTH'
會擲回剖析器例外。 -
在 Spark 3.0 中,以科學記號編寫的數字(例如,
1E2
)將被解析為 Double。在 Spark 版本 2.4 及以下版本中,它們被解析為 Decimal。若要還原 Spark 3.0 之前的行為,您可以將spark.sql.legacy.exponentLiteralAsDecimal.enabled
設為true
。 -
在 Spark 3.0 中,日間時間間隔字串會根據
from
和to
界線轉換為間隔。如果輸入字串與指定界線定義的模式不符,則會擲回ParseException
例外。例如,interval '2 10:20' hour to minute
會引發例外,因為預期的格式為[+|-]h[h]:[m]m
。在 Spark 版本 2.4 中,from
界線未被考慮,而to
界線用於截斷結果間隔。例如,顯示範例中的日間時間間隔字串會轉換為interval 10 hours 20 minutes
。若要還原 Spark 3.0 之前的行為,您可以將spark.sql.legacy.fromDayTimeString.enabled
設為true
。 -
在 Spark 3.0 中,預設不允許小數的負數縮放,例如,像
1E10BD
這樣的文字資料類型為DecimalType(11, 0)
。在 Spark 版本 2.4 及以下版本中,它是DecimalType(2, -9)
。若要還原 Spark 3.0 之前的行為,您可以將spark.sql.legacy.allowNegativeScaleOfDecimal
設為true
。 -
在 Spark 3.0 中,一元算術運算子加號(
+
)僅接受字串、數字和間隔類型值作為輸入。此外,表示整數字串的+
會強制轉換為雙精度值,例如,+'1'
會傳回1.0
。在 Spark 版本 2.4 及以下版本中,此運算子會被忽略。它沒有類型檢查,因此,所有帶有+
前綴的類型值都是有效的,例如,+ array(1, 2)
是有效的,結果為[1, 2]
。此外,它根本沒有類型強制轉換,例如,在 Spark 2.4 中,+'1'
的結果是字串1
。 -
在 Spark 3.0 中,如果 Dataset 查詢包含由自連接產生的不明確欄位參考,則查詢會失敗。一個典型的範例:
val df1 = ...; val df2 = df1.filter(...);
,然後df1.join(df2, df1("a") > df2("a"))
會傳回一個空結果,這相當令人困惑。這是因為 Spark 無法解析指向自連接表的 Dataset 欄位參考,而且df1("a")
在 Spark 中與df2("a")
完全相同。若要回復 Spark 3.0 之前的行為,您可以將spark.sql.analyzer.failAmbiguousSelfJoin
設定為false
。 -
在 Spark 3.0 中,引入了
spark.sql.legacy.ctePrecedencePolicy
來控制嵌套 WITH 子句中名稱衝突的行為。預設值EXCEPTION
,Spark 會擲回 AnalysisException,它強制使用者選擇他們想要的特定替換順序。如果設定為CORRECTED
(建議使用),內部 CTE 定義會優先於外部定義。例如,將設定設定為false
,WITH t AS (SELECT 1), t2 AS (WITH t AS (SELECT 2) SELECT * FROM t) SELECT * FROM t2
會傳回2
,而將其設定為LEGACY
,結果為1
,這是 2.4 以下版本的行為。 -
在 Spark 3.0 中,設定
spark.sql.crossJoin.enabled
變成內部設定,而且預設為 true,因此預設情況下,spark 對於具有隱式交叉連接的 sql 而言不會引發例外。 -
在 Spark 2.4 以下版本中,float/double -0.0 在語意上等於 0.0,但在用於聚合分組鍵、視窗分割鍵和連接鍵時,-0.0 和 0.0 被視為不同的值。在 Spark 3.0 中,此錯誤已修正。例如,
Seq(-0.0, 0.0).toDF("d").groupBy("d").count()
在 Spark 3.0 中會傳回[(0.0, 2)]
,而在 Spark 2.4 以下版本中會傳回[(0.0, 1), (-0.0, 1)]
。 -
在 Spark 2.4 以下版本中,無效時區識別碼會被靜默忽略,並以 GMT 時區取代,例如在 from_utc_timestamp 函數中。在 Spark 3.0 中,此類時區識別碼會被拒絕,而且 Spark 會擲回
java.time.DateTimeException
。 -
在 Spark 3.0 中,Proleptic Gregorian 日曆用於解析、格式化和轉換日期和時間戳記,以及擷取子元件,例如年、日等等。Spark 3.0 使用來自
java.time
套件的 Java 8 API 類別,這些類別基於 ISO 年表。在 Spark 2.4 以下版本中,這些運算使用混合日曆(Julian + Gregorian 執行。這些變更會影響 1582 年 10 月 15 日(格里曆)之前的日期結果,並影響下列 Spark 3.0 API-
時間戳記/日期字串的剖析/格式化。這會影響 CSV/JSON 資料來源和
unix_timestamp
、date_format
、to_unix_timestamp
、from_unixtime
、to_date
、to_timestamp
函式,當使用者指定的模式用於剖析和格式化時。在 Spark 3.0 中,我們在 用於格式化和剖析的日期時間模式 中定義我們自己的模式字串,這是透過 DateTimeFormatter 在幕後實作的。新的實作會對其輸入執行嚴格檢查。例如,如果模式是yyyy-MM-dd
,則無法剖析2015-07-22 10:00:00
時間戳記,因為剖析器不會使用整個輸入。另一個範例是,31/01/2015 00:00
輸入無法由dd/MM/yyyy hh:mm
模式剖析,因為hh
假設小時在1-12
範圍內。在 Spark 版本 2.4 及以下版本中,java.text.SimpleDateFormat
用於時間戳記/日期字串轉換,而支援的模式在 SimpleDateFormat 中說明。可以透過將spark.sql.legacy.timeParserPolicy
設定為LEGACY
來還原舊行為。 -
weekofyear
、weekday
、dayofweek
、date_trunc
、from_utc_timestamp
、to_utc_timestamp
和unix_timestamp
函式使用 java.time API 計算年份的週數、星期中的第幾天,以及 UTC 時區中 TimestampType 值的轉換。 -
JDBC 選項
lowerBound
和upperBound
會以與將字串轉換為 TimestampType/DateType 值相同的方式轉換為 TimestampType/DateType 值。轉換基於前儒略曆 (Proleptic Gregorian calendar),以及 SQL 設定spark.sql.session.timeZone
定義的時區。在 Spark 版本 2.4 及以下版本中,轉換基於混合曆法 (儒略曆 + 儒略曆) 和預設系統時區。 -
格式化
TIMESTAMP
和DATE
文字。 -
從字串建立鍵入的
TIMESTAMP
和DATE
文字。在 Spark 3.0 中,字串轉換為鍵入的TIMESTAMP
/DATE
文字是透過轉換為TIMESTAMP
/DATE
值來執行。例如,TIMESTAMP '2019-12-23 12:59:30'
在語意上等於CAST('2019-12-23 12:59:30' AS TIMESTAMP)
。如果輸入字串不包含時區資訊,則會使用 SQL 設定檔spark.sql.session.timeZone
中的時區。在 Spark 版本 2.4 及以下版本中,轉換會根據 JVM 系統時區進行。預設時區的不同來源可能會變更鍵入的TIMESTAMP
和DATE
文字的行為。
-
-
在 Spark 3.0 中,
TIMESTAMP
文字會使用 SQL 設定檔spark.sql.session.timeZone
轉換為字串。在 Spark 版本 2.4 及以下版本中,轉換會使用 Java 虛擬機的預設時區。 -
在 Spark 3.0 中,Spark 會在與日期/時間戳進行二進位比較時,將
String
轉換為Date/Timestamp
。可以透過將spark.sql.legacy.typeCoercion.datetimeToString.enabled
設為true
來還原Date/Timestamp
轉換為String
的先前行為。 - 在 Spark 3.0 中,支援從字串轉換為日期和時間戳的特殊值。這些值只是在讀取時轉換為一般日期或時間戳值的符號速記。以下字串值支援日期
epoch [zoneId]
- 1970-01-01today [zoneId]
-spark.sql.session.timeZone
指定時區中的目前日期yesterday [zoneId]
- 目前日期 - 1tomorrow [zoneId]
- 目前日期 + 1now
- 執行目前查詢的日期。其概念與 today 相同
例如
SELECT date 'tomorrow' - date 'yesterday';
應輸出2
。以下是特殊時間戳值epoch [zoneId]
- 1970-01-01 00:00:00+00 (Unix 系統時間零)今天 [zoneId]
- 今天的午夜昨天 [zoneId]
- 昨天的午夜明天 [zoneId]
- 明天的午夜現在
- 目前查詢的開始時間
例如
SELECT timestamp '明天';
。 -
自 Spark 3.0 起,使用
EXTRACT
表達式從日期/時間戳記值中提取第二個欄位時,結果將會是DecimalType(8, 6)
值,其中第二個部分有 2 個數字,小數部分有 6 個數字,具有微秒精度。例如extract(second from to_timestamp('2019-09-20 10:10:10.1'))
的結果為10.100000
。在 Spark 版本 2.4 及更早版本中,它會傳回IntegerType
值,而前述範例的結果為10
。 -
在 Spark 3.0 中,日期時間模式字母
F
是與月份對齊的星期幾,表示在星期期間的天數計數概念,其中星期與月份的開始對齊。在 Spark 版本 2.4 及更早版本中,它是月份的星期,表示在月份中星期數的計數概念,其中星期從固定的星期幾開始,例如2020-07-30
是月份的第一天後的 30 天(4 個星期和 2 天),因此date_format(date '2020-07-30', 'F')
在 Spark 3.0 中傳回 2,但在 Spark 2.x 中作為星期數計數,它傳回 5,因為它位於 2020 年 7 月的第 5 個星期,其中第一個星期是 2020-07-01 至 07-04。 -
在 Spark 3.0 中,Spark 會嘗試在
CTAS
中使用內建資料來源寫入器,而不是 Hive serde。此行為僅在分別針對 Parquet 和 ORC 格式啟用spark.sql.hive.convertMetastoreParquet
或spark.sql.hive.convertMetastoreOrc
時才會生效。若要還原 Spark 3.0 之前的行為,您可以將spark.sql.hive.convertMetastoreCtas
設定為false
。 - 在 Spark 3.0 中,Spark 會嘗試使用內建資料來源寫入器,而不是 Hive serde 來處理插入使用 HiveSQL 語法建立的分區 ORC/Parquet 表格。此行為僅在
spark.sql.hive.convertMetastoreParquet
或spark.sql.hive.convertMetastoreOrc
分別針對 Parquet 和 ORC 格式啟用時才會生效。若要還原 Spark 3.0 之前的行為,您可以將spark.sql.hive.convertInsertingPartitionedTable
設為false
。
資料來源
-
在 Spark 版本 2.4 及以下版本中,當使用 Spark 原生資料來源 (parquet/orc) 讀取 Hive SerDe 表格時,Spark 會推斷實際檔案架構並更新 metastore 中的表格架構。在 Spark 3.0 中,Spark 不再推斷架構。這不應會對最終使用者造成任何問題,但如果確實造成問題,請將
spark.sql.hive.caseSensitiveInferenceMode
設為INFER_AND_SAVE
。 -
在 Spark 版本 2.4 及以下版本中,如果無法將分區欄位值轉換為對應使用者提供的架構,則該值會轉換為 null。在 3.0 中,分區欄位值會使用使用者提供的架構進行驗證。如果驗證失敗,則會擲回例外。您可以透過將
spark.sql.sources.validatePartitionColumns
設為false
來停用此類驗證。 -
在 Spark 3.0 中,如果在遞迴目錄清單中檔案或子目錄消失 (亦即,它們出現在中間清單中,但由於同時刪除檔案或物件儲存一致性問題,而在遞迴目錄清單的後續階段無法讀取或列出它們),則清單會失敗並擲回例外,除非
spark.sql.files.ignoreMissingFiles
為true
(預設為false
)。在先前版本中,這些遺失的檔案或子目錄會被忽略。請注意,此行為變更僅適用於初始表格檔案清單 (或在REFRESH TABLE
期間),不適用於查詢執行:淨變更為spark.sql.files.ignoreMissingFiles
現在會在表格檔案清單/查詢規劃期間遵守,而不再僅在查詢執行時間遵守。 -
在 Spark 2.4 及以下版本中,JSON 資料來源的剖析器會將某些資料類型(例如
IntegerType
)的空字串視為 null。對於FloatType
、DoubleType
、DateType
和TimestampType
,它會在遇到空字串時失敗並擲回例外。Spark 3.0 不允許空字串,並且會對StringType
和BinaryType
以外的資料類型擲回例外。可以透過將spark.sql.legacy.json.allowEmptyString.enabled
設為true
來還原先前允許空字串的行為。 -
在 Spark 2.4 及以下版本中,當指定架構為
StructType
時,JSON 資料來源和 JSON 函式(例如from_json
)會在寬容模式中將錯誤的 JSON 記錄轉換成一列,其中所有null
出現在 PERMISSIVE 模式中。在 Spark 3.0 中,如果某些 JSON 欄位值已成功剖析並轉換成所需的類型,則傳回的列可能包含非null
欄位。 -
在 Spark 3.0 中,如果 JSON 資料來源和 JSON 函式
schema_of_json
的字串值符合 JSON 選項timestampFormat
定義的模式,則會從字串值推論出 TimestampType。將 JSON 選項inferTimestamp
設為false
以停用此類型的推論。 -
在 Spark 2.4 及以下版本中,CSV 資料來源會將格式錯誤的 CSV 字串轉換成一列,其中所有
null
出現在 PERMISSIVE 模式中。在 Spark 3.0 中,如果某些 CSV 欄位值已成功剖析並轉換成所需的類型,則傳回的列可能包含非null
欄位。 -
在 Spark 3.0 中,當 Avro 檔案使用使用者提供的架構撰寫時,欄位會根據催化劑架構和 Avro 架構之間的欄位名稱進行比對,而不是根據位置進行比對。
-
在 Spark 3.0 中,當 Avro 檔案使用使用者提供的不可為 null 的架構撰寫時,即使催化劑架構為可為 null,Spark 仍可以撰寫檔案。但是,如果任何記錄包含 null,Spark 會擲回執行時期 NullPointerException。
-
在 Spark 2.4 及以下版本中,當檔案開頭有 BOM 時,CSV 資料來源可以自動偵測輸入檔案的編碼。例如,CSV 資料來源可以在多行模式下辨識 UTF-8、UTF-16BE、UTF-16LE、UTF-32BE 和 UTF-32LE(CSV 選項
multiLine
設為true
)。在 Spark 3.0 中,CSV 資料來源會以 CSV 選項encoding
指定的編碼讀取輸入檔案,而該選項的預設值為 UTF-8。如此一來,如果檔案編碼與透過 CSV 選項指定的編碼不符,Spark 就會錯誤載入檔案。要解決這個問題,使用者應透過 CSV 選項encoding
設定正確的編碼,或將選項設為null
,讓編碼自動偵測回歸到 Spark 3.0 之前的版本。
其他
-
在 Spark 2.4 版本中,當 Spark 工作階段是透過
cloneSession()
建立時,新建立的 Spark 工作階段會從其父項SparkContext
繼承其組態,即使其父項 Spark 工作階段中存在相同組態但值不同。在 Spark 3.0 中,父項SparkSession
的組態優先於父項SparkContext
。你可以透過將spark.sql.legacy.sessionInitWithConfigDefaults
設為true
來還原舊有行為。 -
在 Spark 3.0 中,如果在
Spark SQL 組態
中找不到hive.default.fileformat
,它會回歸到SparkContext
的Hadoop 組態
中的hive-site.xml
檔案。 -
在 Spark 3.0 中,我們會將小數數字補上尾數零,以符合
spark-sql
介面的欄位縮放,例如查詢 Spark 2.4 Spark 3.0 SELECT CAST(1 AS decimal(38, 18));
1 1.000000000000000000 -
在 Spark 3.0 中,我們將內建的 Hive 從 1.2 升級到 2.3,並帶來以下影響
-
你可能需要根據要連線的 Hive Metastore 版本設定
spark.sql.hive.metastore.version
和spark.sql.hive.metastore.jars
。例如:如果你的 Hive Metastore 版本是 1.2.1,請將spark.sql.hive.metastore.version
設為1.2.1
,並將spark.sql.hive.metastore.jars
設為maven
。 -
你需要將自訂 SerDes 移轉到 Hive 2.3,或使用
hive-1.2
設定檔建立自己的 Spark。請參閱 HIVE-15167 以取得更多詳細資訊。 -
在 SQL 中使用
TRANSFORM
算子進行指令碼轉換時,Hive 1.2 和 Hive 2.3 之間的小數字串表示方式可能不同,這取決於 Hive 的行為。在 Hive 1.2 中,字串表示方式會省略尾數零。但在 Hive 2.3 中,如果需要,它會始終補上 18 個位數的尾數零。
-
從 Spark SQL 2.4.7 升級至 2.4.8
- 在 Spark 2.4.8 中,
AnalysisException
已被其子類別取代,這些子類別會在下列情況下針對 Hive 外部目錄中的資料表擲出ALTER TABLE .. ADD PARTITION
如果新分區已存在,則會擲出PartitionsAlreadyExistException
ALTER TABLE .. DROP PARTITION
如果分區不存在,則會擲出NoSuchPartitionsException
從 Spark SQL 2.4.5 升級至 2.4.6
- 在 Spark 2.4.6 中,
RESET
指令不會將靜態 SQL 組態值重設為預設值。它只會清除執行時期 SQL 組態值。
從 Spark SQL 2.4.4 升級至 2.4.5
-
自 Spark 2.4.5 以來,
TRUNCATE TABLE
指令會嘗試在重新建立資料表/分割區路徑時設定回原始權限和 ACL。若要還原較早版本的行為,請將spark.sql.truncateTable.ignorePermissionAcl.enabled
設為true
。 -
自 Spark 2.4.5 以來,已新增
spark.sql.legacy.mssqlserver.numericMapping.enabled
組態,以支援使用 IntegerType 和 DoubleType 分別對應 SMALLINT 和 REAL JDBC 類型的舊版 MsSQLServer 方言對應行為。若要還原 2.4.3 及較早版本的行為,請將spark.sql.legacy.mssqlserver.numericMapping.enabled
設為true
。
從 Spark SQL 2.4.3 升級至 2.4.4
- 自 Spark 2.4.4 以來,根據 MsSqlServer 指南,MsSQLServer JDBC 方言分別使用 ShortType 和 FloatType 對應 SMALLINT 和 REAL。先前使用的是 IntegerType 和 DoubleType。
從 Spark SQL 2.4 升級至 2.4.1
- 在 Spark 2.4.0 中,當未指定單位(例如「30」而非「30s」)時,
spark.executor.heartbeatInterval
的值在程式碼的不同部分中被不一致地解譯為秒和毫秒。現在,無單位的數值會一致地解譯為毫秒。設定「30」等值的應用程式現在需要指定帶有單位(例如「30s」)的值,以避免被解譯為毫秒;否則,產生的極短間隔可能會導致應用程式失敗。
從 Spark SQL 2.3 升級至 2.4
- 在 Spark 版本 2.3 及更早版本中,array_contains 函式的第二個參數會隱式提升為第一個陣列類型參數的元素類型。這種類型提升可能會造成資料遺失,並可能導致
array_contains
函式傳回錯誤的結果。此問題已在 2.4 中透過採用更安全的類型提升機制解決。這可能會造成一些行為改變,並在下表中說明。查詢 Spark 2.3 或更早版本 Spark 2.4 備註 SELECT array_contains(array(1), 1.34D);
true
false
在 Spark 2.4 中,left 和 right 參數分別提升為雙精度類型和雙精度類型的陣列類型。 SELECT array_contains(array(1), '1');
true
會擲出 AnalysisException
。可以在參數中使用明確轉換來避免例外。在 Spark 2.4 中,會擲出 AnalysisException
,因為整數類型無法以無損失的方式提升為字串類型。SELECT array_contains(array(1), 'anystring');
null
會擲出 AnalysisException
。可以在參數中使用明確轉換來避免例外。在 Spark 2.4 中,會擲出 AnalysisException
,因為整數類型無法以無損失的方式提升為字串類型。 -
自 Spark 2.4 起,當子查詢前的 IN 運算子前面有結構欄位時,內部查詢也必須包含結構欄位。在以前的版本中,結構的欄位會與內部查詢的輸出進行比較。例如,如果
a
是struct(a string, b int)
,在 Spark 2.4 中a in (select (1 as a, 'a' as b) from range(1))
是有效的查詢,而a in (select 1, 'a' from range(1))
則不是。在以前的版本中則相反。 -
在 2.2.1+ 和 2.3 版本中,如果將
spark.sql.caseSensitive
設為 true,則CURRENT_DATE
和CURRENT_TIMESTAMP
函數會不正確地變成大小寫敏感,並會解析為欄位 (除非輸入小寫)。在 Spark 2.4 中已修正此問題,而這些函數不再大小寫敏感。 -
自 Spark 2.4 起,Spark 會根據 SQL 標準遵循優先順序規則來評估查詢中引用的集合運算。如果未透過括號指定順序,集合運算會由左至右執行,但例外情況是所有 INTERSECT 運算會在任何 UNION、EXCEPT 或 MINUS 運算之前執行。在新增的設定檔
spark.sql.legacy.setopsPrecedence.enabled
中保留了對所有集合運算賦予相同優先順序的舊行為,其預設值為false
。當此屬性設為true
時,Spark 會由左至右評估集合運算,因為在查詢中出現時未強制使用括號來執行明確排序。 -
自 Spark 2.4 起,當值為 1970 年 1 月 1 日時,Spark 會將資料表說明欄位最後存取值顯示為 UNKNOWN。
-
自 Spark 2.4 起,Spark 預設會將向量化 ORC 讀取器用於 ORC 檔案,以最大化其使用率。為此,
spark.sql.orc.impl
和spark.sql.orc.filterPushdown
會將其預設值分別變更為native
和true
。由原生 ORC 寫入器建立的 ORC 檔案無法由部分舊版 Apache Hive 讀取。請使用spark.sql.orc.impl=hive
來建立與 Hive 2.1.1 及更舊版本共用的檔案。 -
自 Spark 2.4 起,將空資料框寫入目錄會啟動至少一個寫入工作,即使資料框在實體上沒有分割區。這會造成一個小的行為變更,對於 Parquet 和 Orc 等自述檔案格式,Spark 會在寫入 0 分割區資料框時在目標目錄中建立一個僅含元資料的檔案,以便使用者稍後讀取該目錄時,架構推論仍然可以運作。新的行為在寫入空資料框時更為合理且更一致。
-
自 Spark 2.4 起,UDF 引數中的表達式 ID 不會出現在欄位名稱中。例如,Spark 2.4 中的欄位名稱不是
UDF:f(col0 AS colA#28)
,而是UDF:f(col0 AS `colA`)
。 -
自 Spark 2.4 起,不允許使用任何檔案格式 (parquet、orc、json、text、csv 等) 寫入具有空或巢狀空架構的資料框。嘗試寫入具有空架構的資料框時,會擲回例外狀況。
-
自 Spark 2.4 起,Spark 會在將兩側都提升為 TIMESTAMP 之後,比較 DATE 類型和 TIMESTAMP 類型。將
spark.sql.legacy.compareDateTimestampInTimestamp
設為false
會還原先前的行為。此選項將在 Spark 3.0 中移除。 -
自 Spark 2.4 起,不允許建立具有非空位置的管理式資料表。嘗試建立具有非空位置的管理式資料表時,會擲回例外狀況。將
spark.sql.legacy.allowCreatingManagedTableUsingNonemptyLocation
設為true
會還原先前的行為。此選項將在 Spark 3.0 中移除。 -
自 Spark 2.4 起,不允許將管理式資料表重新命名為現有位置。嘗試將管理式資料表重新命名為現有位置時,會擲回例外狀況。
-
自 Spark 2.4 起,類型強制轉換規則可以自動將可變參數 SQL 函數 (例如 IN/COALESCE) 的引數類型提升為最廣泛的共用類型,無論輸入引數的順序為何。在先前的 Spark 版本中,提升可能會在某些特定順序 (例如 TimestampType、IntegerType 和 StringType) 中失敗,並擲回例外狀況。
-
自 Spark 2.4 起,Spark 已啟用非連鎖 SQL 快取失效,以搭配傳統的快取失效機制。非連鎖快取失效機制允許使用者移除快取,而不會影響其相依快取。此新的快取失效機制用於快取資料仍然有效的場景,例如對 Dataset 呼叫 unpersist(),或刪除暫時檢視。這允許使用者同時釋放記憶體並保持所需的快取有效。
-
在 2.3 及更早版本中,Spark 預設會轉換 Parquet Hive 表格,但會忽略表格屬性,例如
TBLPROPERTIES (parquet.compression 'NONE')
。如果spark.sql.hive.convertMetastoreOrc=true
,也會發生在 ORC Hive 表格屬性,例如TBLPROPERTIES (orc.compress 'NONE')
。從 Spark 2.4 開始,Spark 會在轉換 Parquet/ORC Hive 表格時尊重 Parquet/ORC 特定的表格屬性。舉例來說,CREATE TABLE t(id int) STORED AS PARQUET TBLPROPERTIES (parquet.compression 'NONE')
會在 Spark 2.3 中插入時產生 Snappy Parquet 檔案,而在 Spark 2.4 中,結果會是未壓縮的 Parquet 檔案。 -
從 Spark 2.0 開始,Spark 預設會轉換 Parquet Hive 表格以提升效能。從 Spark 2.4 開始,Spark 也會預設轉換 ORC Hive 表格。這表示 Spark 預設會使用自己的 ORC 支援,而不是 Hive SerDe。舉例來說,
CREATE TABLE t(id int) STORED AS ORC
會在 Spark 2.3 中使用 Hive SerDe 處理,而在 Spark 2.4 中,它會轉換成 Spark 的 ORC 資料來源表格,並套用 ORC 向量化。將spark.sql.hive.convertMetastoreOrc
設為false
可還原為之前的行為。 -
在 2.3 及更早版本中,如果列中至少有一個欄位值有問題,CSV 列會被視為格式錯誤。CSV 剖析器會在 DROPMALFORMED 模式中捨棄這些列,或是在 FAILFAST 模式中輸出錯誤。從 Spark 2.4 開始,只有當 CSV 資料來源請求的 CSV 列包含格式錯誤的欄位值時,才會將該列視為格式錯誤,其他值可以忽略。舉例來說,CSV 檔案包含「id,name」標頭和一列「1234」。在 Spark 2.4 中,選取 id 欄位會包含一列欄位值為 1234 的列,但在 Spark 2.3 及更早版本中,它在 DROPMALFORMED 模式中會是空的。若要還原為之前的行為,請將
spark.sql.csv.parser.columnPruning.enabled
設為false
。 -
從 Spark 2.4 開始,預設會並行進行檔案清單統計計算。這可以透過將
spark.sql.statistics.parallelFileListingInStatsComputation.enabled
設為False
來停用。 -
自 Spark 2.4 起,在統計計算期間計算資料表大小時,不會將元資料檔案(例如 Parquet 摘要檔案)和暫存檔案計為資料檔案。
-
自 Spark 2.4 起,空字串會儲存為帶引號的空字串
""
。在版本 2.3 及更早版本中,空字串等於null
值,且不會反映在已儲存的 CSV 檔案中的任何字元。例如,"a", null, "", 1
的列寫成a,,,1
。自 Spark 2.4 起,同一列儲存為a,,"",1
。若要還原先前的行為,請將 CSV 選項emptyValue
設定為空字串(不帶引號)。 -
自 Spark 2.4 起,LOAD DATA 指令支援萬用字元
?
和*
,分別用於比對任何一個字元和零個或多個字元。範例:LOAD DATA INPATH '/tmp/folder*/'
或LOAD DATA INPATH '/tmp/part-?'
。現在,路徑中也支援特殊字元,例如space
。範例:LOAD DATA INPATH '/tmp/folder name/'
。 -
在 Spark 版本 2.3 及更早版本中,沒有 GROUP BY 的 HAVING 會視為 WHERE。這表示
SELECT 1 FROM range(10) HAVING true
會執行為SELECT 1 FROM range(10) WHERE true
,並傳回 10 列。這違反了 SQL 標準,且已在 Spark 2.4 中修正。自 Spark 2.4 起,沒有 GROUP BY 的 HAVING 會視為全域聚合,這表示SELECT 1 FROM range(10) HAVING true
只會傳回一列。若要還原先前的行為,請將spark.sql.legacy.parser.havingWithoutGroupByAsWhere
設定為true
。 - 在 2.3 及更早版本中,當從 Parquet 資料來源表格讀取時,如果 Hive metastore 結構和 Parquet 結構中的欄位名稱使用不同的字母大小寫,Spark 會永遠傳回 null,無論
spark.sql.caseSensitive
設定為true
或false
。自 2.4 以後,當spark.sql.caseSensitive
設定為false
時,Spark 會在 Hive metastore 結構和 Parquet 結構之間進行不區分大小寫的欄位名稱解析,因此即使欄位名稱使用不同的字母大小寫,Spark 仍會傳回對應的欄位值。如果出現歧義(即配對到多個 Parquet 欄位),則會擲回例外。當spark.sql.hive.convertMetastoreParquet
設定為true
時,這個變更也會套用於 Parquet Hive 表格。
從 Spark SQL 2.2 升級至 2.3
-
自 Spark 2.3 以後,當參照的欄位只包含內部損毀記錄欄位(預設名稱為
_corrupt_record
)時,將不允許從原始 JSON/CSV 檔案進行查詢。例如,spark.read.schema(schema).json(file).filter($"_corrupt_record".isNotNull).count()
和spark.read.schema(schema).json(file).select("_corrupt_record").show()
。您可改為快取或儲存已剖析的結果,然後再傳送相同的查詢。例如,val df = spark.read.schema(schema).json(file).cache()
,然後df.filter($"_corrupt_record".isNotNull).count()
。 -
percentile_approx
函數先前接受數值型別輸入並輸出雙精度型別結果。現在它支援日期型別、時間戳記型別和數值型別作為輸入型別。結果型別也變更為與輸入型別相同,這對於百分比來說較為合理。 -
自 Spark 2.3 以後,如果可行,Join/Filter 的確定性謂詞(位於第一個非確定性謂詞之後)也會推入/傳遞至子運算子。在先前的 Spark 版本中,這些篩選器不符合謂詞推入的資格。
-
分割欄位推論先前會為不同的推論型別找到不正確的共用型別,例如,先前它會以雙精度型別作為雙精度型別和日期型別的共用型別。現在它會為此類衝突找到正確的共用型別。衝突解決遵循下表
InputA \ InputB NullType IntegerType LongType DecimalType(38,0)* DoubleType 日期類型 時間戳記類型 字串類型
</thead> <tr> <td> NullType </td> <td>NullType</td> <td>IntegerType</td> <td>LongType</td> <td>DecimalType(38,0)</td> <td>DoubleType</td> <td>DateType</td> <td>TimestampType</td> <td>StringType</td> </tr> <tr> <td> IntegerType </td> <td>IntegerType</td> <td>IntegerType</td> <td>LongType</td> <td>DecimalType(38,0)</td> <td>DoubleType</td> <td>StringType</td> <td>StringType</td> <td>StringType</td> </tr> <tr> <td> LongType </td> <td>LongType</td> <td>LongType</td> <td>LongType</td> <td>DecimalType(38,0)</td> <td>StringType</td> <td>StringType</td> <td>StringType</td> <td>StringType</td> </tr> <tr> <td> DecimalType(38,0)* </td> <td>DecimalType(38,0)</td> <td>DecimalType(38,0)</td> <td>DecimalType(38,0)</td> <td>DecimalType(38,0)</td> <td>StringType</td> <td>StringType</td> <td>StringType</td> <td>StringType</td> </tr> <tr> <td> DoubleType </td> <td>DoubleType</td> <td>DoubleType</td> <td>StringType</td> <td>StringType</td> <td>DoubleType</td> <td>StringType</td> <td>StringType</td> <td>StringType</td> </tr> <tr> <td> DateType </td> <td>DateType</td> <td>StringType</td> <td>StringType</td> <td>StringType</td> <td>StringType</td> <td>DateType</td> <td>TimestampType</td> <td>StringType</td> </tr> <tr> <td> TimestampType </td> <td>TimestampType</td> <td>StringType</td> <td>StringType</td> <td>StringType</td> <td>StringType</td> <td>TimestampType</td> <td>TimestampType</td> <td>StringType</td> </tr> <tr> <td> StringType </td> <td>StringType</td> <td>StringType</td> <td>StringType</td> <td>StringType</td> <td>StringType</td> <td>StringType</td> <td>StringType</td> <td>StringType</td> </tr> </table>
Note that, for <b>DecimalType(38,0)*</b>, the table above intentionally does not cover all other combinations of scales and precisions because currently we only infer decimal type like `BigInteger`/`BigInt`. For example, 1.1 is inferred as double type.
-
自 Spark 2.3 起,當廣播雜湊聯結或廣播巢狀迴圈聯結適用時,我們偏好廣播在廣播提示中明確指定的表格。有關詳細資訊,請參閱區段 SQL 查詢的聯結策略提示 和 SPARK-22489。
-
自 Spark 2.3 起,當所有輸入都是二進位時,
functions.concat()
會傳回二進位輸出的結果。否則,會傳回字串。在 Spark 2.3 之前,它始終會傳回字串,不論輸入類型為何。若要維持舊有行為,請將spark.sql.function.concatBinaryAsString
設為true
。 -
自 Spark 2.3 起,當所有輸入都是二進位時,SQL
elt()
會傳回二進位輸出的結果。否則,會傳回字串。在 Spark 2.3 之前,它始終會傳回字串,不論輸入類型為何。若要維持舊有行為,請將spark.sql.function.eltOutputAsString
設為true
。 -
自 Spark 2.3 起,如果無法精確表示,預設的十進位運算會傳回捨入值(而不是傳回 NULL)。這符合 SQL ANSI 2011 規格,以及 Hive 2.2(HIVE-15331)中引入的 Hive 新行為。這涉及下列變更
-
已更新決定運算結果類型的規則。特別是,如果所需的精確度/縮放超出可用值的範圍,則縮放會減少到 6,以防止十進位數整數部分的截斷。所有運算都會受到變更的影響,例如加法 (
+
)、減法 (-
)、乘法 (*
)、除法 (/
)、餘數 (%
) 和正模數 (pmod
)。 -
在 SQL 運算中使用的文字值會轉換為十進位數,其精確度和縮放與其所需的一致。
-
已引入設定
spark.sql.decimalOperations.allowPrecisionLoss
。其預設值為true
,表示在此描述的新行為;如果設定為false
,Spark 會使用先前的規則,也就是說,它不會調整所需的縮放來表示值,如果無法精確表示值,則會傳回 NULL。
-
-
未別名的子查詢語意定義不佳,行為令人困惑。自 Spark 2.3 起,我們會使這種令人困惑的情況失效,例如:
SELECT v.i from (SELECT i FROM v)
,Spark 會在此情況下擲回分析例外,因為使用者不應能在子查詢中使用限定詞。請參閱 SPARK-20690 和 SPARK-21335 以取得更多詳細資料。 -
使用
SparkSession.builder.getOrCreate()
建立SparkSession
時,如果已存在SparkContext
,則建構函式會嘗試使用指定給建構函式的組態更新現有SparkContext
的SparkConf
,但SparkContext
由所有SparkSession
共用,因此我們不應更新它們。自 2.3 以來,建構函式就不再更新組態。如果您想要更新它們,您需要在建立SparkSession
之前更新它們。
從 Spark SQL 2.1 升級至 2.2
-
Spark 2.1.1 導入了一個新的組態金鑰:
spark.sql.hive.caseSensitiveInferenceMode
。它的預設設定為NEVER_INFER
,這讓行為與 2.1.0 相同。然而,Spark 2.2.0 將此設定的預設值變更為INFER_AND_SAVE
,以恢復與讀取底層檔案架構具有混合大小寫欄位名稱的 Hive Metastore 資料表的相容性。使用INFER_AND_SAVE
組態值時,Spark 會在第一次存取任何 Hive Metastore 資料表時,對該資料表執行架構推論,而 Spark 尚未為該資料表儲存推論的架構。請注意,對於具有數千個分割區的資料表,架構推論可能是一個非常耗時的作業。如果相容性與混合大小寫欄位名稱無關,您可以安全地將spark.sql.hive.caseSensitiveInferenceMode
設定為NEVER_INFER
,以避免架構推論的初始負擔。請注意,使用新的預設INFER_AND_SAVE
設定時,架構推論的結果會儲存為 Metastore 金鑰,以供未來使用。因此,初始架構推論只會在資料表的第一次存取時發生。 -
自 Spark 2.2.1 和 2.3.0 以來,當資料來源資料表具有存在於分割區架構和資料架構中的欄位時,架構會在執行階段始終推論。推論的架構沒有分割的欄位。在讀取資料表時,Spark 會尊重這些重疊欄位的分割值,而不是儲存在資料來源檔案中的值。在 2.2.0 和 2.1.x 版本中,推論的架構是分割的,但資料表的資料對使用者來說是不可見的(即,結果集是空的)。
-
自 Spark 2.2 以來,檢視定義的儲存方式與先前版本不同。這可能會導致 Spark 無法讀取由先前版本建立的檢視。在這種情況下,您需要使用較新的 Spark 版本,透過
ALTER VIEW AS
或CREATE OR REPLACE VIEW AS
重新建立檢視。
從 Spark SQL 2.0 升級至 2.1
-
資料庫來源表格現在會將分割資料儲存在 Hive 的 metastore 中。這表示現在可以使用 Hive DDL,例如
ALTER TABLE PARTITION ... SET LOCATION
,來處理使用資料庫來源 API 建立的表格。-
可以透過
MSCK REPAIR TABLE
指令,將舊版的資料庫來源表格移轉至這種格式。建議移轉舊版表格,以利用 Hive DDL 支援和改善規劃效能。 -
若要判斷表格是否已移轉,請在表格上執行
DESCRIBE FORMATTED
時,尋找PartitionProvider: Catalog
屬性。
-
-
變更資料庫來源表格的
INSERT OVERWRITE TABLE ... PARTITION ...
行為。-
在先前的 Spark 版本中,
INSERT OVERWRITE
會覆寫整個資料庫來源表格,即使給定分割規格。現在,只會覆寫符合規格的分割。 -
請注意,這仍然與 Hive 表格的行為不同,後者的行為是只覆寫與新插入資料重疊的分割。
-
從 Spark SQL 1.6 升級至 2.0
-
SparkSession
現在是 Spark 的新進入點,取代舊的SQLContext
和HiveContext
。請注意,舊的 SQLContext 和 HiveContext 會保留,以維持向後相容性。新的catalog
介面可從SparkSession
存取,現有的資料庫和表格存取 API,例如listTables
、createExternalTable
、dropTempView
、cacheTable
,已移至此處。 -
Dataset API 和 DataFrame API 已統一。在 Scala 中,
DataFrame
成為Dataset[Row]
的類型別名,而 Java API 使用者必須將DataFrame
取代為Dataset<Row>
。Dataset 類別中同時提供型別轉換(例如map
、filter
和groupByKey
)和未型別轉換(例如select
和groupBy
)。由於 Python 和 R 中的編譯時期類型安全性並非語言功能,因此 Dataset 的概念不適用於這些語言的 API。取而代之的是,DataFrame
仍然是主要的程式抽象,這類似於這些語言中單一節點資料框的概念。 -
資料集和資料框 API
unionAll
已棄用,並已由union
取代 -
資料集和資料框 API
explode
已棄用,或者使用functions.explode()
搭配select
或flatMap
-
資料集和資料框 API
registerTempTable
已棄用,並已由createOrReplaceTempView
取代 -
變更
CREATE TABLE ... LOCATION
行為,以適用於 Hive 資料表。-
從 Spark 2.0 開始,
CREATE TABLE ... LOCATION
等同於CREATE EXTERNAL TABLE ... LOCATION
,以避免意外刪除使用者提供的資料夾中的現有資料。這表示,在 Spark SQL 中建立的 Hive 資料表,其使用者指定的資料夾位置永遠都是 Hive 外部資料表。刪除外部資料表不會移除資料。使用者無法為 Hive 管理的資料表指定資料夾位置。請注意,這與 Hive 行為不同。 -
因此,對這些資料表執行的
DROP TABLE
陳述式不會移除資料。
-
-
spark.sql.parquet.cacheMetadata
已不再使用。有關詳細資訊,請參閱 SPARK-13664。
從 Spark SQL 1.5 升級至 1.6
- 從 Spark 1.6 開始,Thrift 伺服器預設以多重工作階段模式執行。這表示每個 JDBC/ODBC 連線都擁有自己的 SQL 組態和暫時函式登錄檔的副本。但快取資料表仍會共用。如果您偏好以舊的單一工作階段模式執行 Thrift 伺服器,請將選項
spark.sql.hive.thriftServer.singleSession
設定為true
。您可以將此選項新增至spark-defaults.conf
,或透過--conf
傳遞至start-thriftserver.sh
./sbin/start-thriftserver.sh \
--conf spark.sql.hive.thriftServer.singleSession=true \
...
- 從 Spark 1.6 開始,LongType 轉換為 TimestampType 預期為秒,而非微秒。這項變更的目的是為了符合 Hive 1.2 的行為,以更一致地將數值類型轉換為 TimestampType。有關詳細資訊,請參閱 SPARK-11724。
從 Spark SQL 1.4 升級至 1.5
-
預設情況下,現在已啟用使用手動管理的記憶體(Tungsten)進行最佳化執行,以及用於表達式評估的程式碼產生。這些功能都可以透過將
spark.sql.tungsten.enabled
設定為false
來停用。 -
Parquet 架構合併不再是預設啟用。它可以透過將
spark.sql.parquet.mergeSchema
設定為true
來重新啟用。 -
預設情況下已開啟記憶體中欄式儲存區分割區篩選。它可以透過將
spark.sql.inMemoryColumnarStorage.partitionPruning
設定為false
來停用。 -
不再支援無限精度的十進位數欄,而 Spark SQL 強制執行 38 的最大精度。從
BigDecimal
物件推斷架構時,現在使用 (38, 18) 的精度。如果在 DDL 中未指定精度,預設值仍為Decimal(10, 0)
。 -
時間戳記現在以 1us 的精度儲存,而不是 1ns
-
在
sql
方言中,浮點數現在被解析為十進位數。HiveQL 解析保持不變。 -
SQL/DataFrame 函數的正規名稱現在是小寫(例如,sum 與 SUM)。
-
JSON 資料來源不會自動載入由其他應用程式建立的新檔案(即未透過 Spark SQL 插入至資料集的檔案)。對於 JSON 持久表(即表的元資料儲存在 Hive Metastore 中),使用者可以使用
REFRESH TABLE
SQL 指令或HiveContext
的refreshTable
方法將這些新檔案包含至表中。對於代表 JSON 資料集的 DataFrame,使用者需要重新建立 DataFrame,而新的 DataFrame 將包含新檔案。
從 Spark SQL 1.3 升級至 1.4
DataFrame 資料讀取器/寫入器介面
根據使用者的回饋,我們建立了一個新的、更流暢的 API 來讀取資料(SQLContext.read
)和寫出資料(DataFrame.write
),並棄用舊的 API(例如 SQLContext.parquetFile
、SQLContext.jsonFile
)。
請參閱 SQLContext.read
( Scala、Java、Python ) 和 DataFrame.write
( Scala、Java、Python ) 的 API 文件,以取得更多資訊。
DataFrame.groupBy 保留群組欄
根據使用者的回饋,我們已將 DataFrame.groupBy().agg()
的預設行為變更為在結果 DataFrame
中保留群組欄。若要保留 1.3 中的行為,請將 spark.sql.retainGroupColumns
設定為 false
。
import pyspark.sql.functions as func
# In 1.3.x, in order for the grouping column "department" to show up,
# it must be included explicitly as part of the agg function call.
df.groupBy("department").agg(df["department"], func.max("age"), func.sum("expense"))
# In 1.4+, grouping column "department" is included automatically.
df.groupBy("department").agg(func.max("age"), func.sum("expense"))
# Revert to 1.3.x behavior (not retaining grouping column) by:
sqlContext.setConf("spark.sql.retainGroupColumns", "false")
// In 1.3.x, in order for the grouping column "department" to show up,
// it must be included explicitly as part of the agg function call.
df.groupBy("department").agg($"department", max("age"), sum("expense"))
// In 1.4+, grouping column "department" is included automatically.
df.groupBy("department").agg(max("age"), sum("expense"))
// Revert to 1.3 behavior (not retaining grouping column) by:
sqlContext.setConf("spark.sql.retainGroupColumns", "false")
// In 1.3.x, in order for the grouping column "department" to show up,
// it must be included explicitly as part of the agg function call.
df.groupBy("department").agg(col("department"), max("age"), sum("expense"));
// In 1.4+, grouping column "department" is included automatically.
df.groupBy("department").agg(max("age"), sum("expense"));
// Revert to 1.3 behavior (not retaining grouping column) by:
sqlContext.setConf("spark.sql.retainGroupColumns", "false");
DataFrame.withColumn 的行為變更
在 1.4 之前,DataFrame.withColumn() 僅支援新增欄位。即使結果 DataFrame 中可能已有同名的欄位,該欄位仍會以指定的欄位名稱新增為新欄位。自 1.4 起,DataFrame.withColumn() 支援新增與所有現有欄位名稱不同的欄位,或取代同名的現有欄位。
請注意,此變更僅適用於 Scala API,不適用於 PySpark 和 SparkR。
從 Spark SQL 1.0-1.2 升級至 1.3
在 Spark 1.3 中,我們移除了 Spark SQL 的「Alpha」標籤,並作為此變更的一部分清理了可用的 API。從 Spark 1.3 起,Spark SQL 將提供與 1.X 系列中其他版本的二進位相容性。此相容性保證不包括明確標示為不穩定的 API(例如 DeveloperAPI 或 Experimental)。
SchemaRDD 改名為 DataFrame
使用者在升級到 Spark SQL 1.3 時會注意到的最大變更,就是 SchemaRDD
已改名為 DataFrame
。這主要是因為 DataFrames 不再直接繼承 RDD,而是透過自己的實作提供 RDD 提供的大部分功能。DataFrames 仍可透過呼叫 .rdd
方法轉換為 RDD。
在 Scala 中,SchemaRDD
有別名 DataFrame
,可提供部分使用案例的原始相容性。仍建議使用者更新其程式碼,改用 DataFrame
。Java 和 Python 使用者需要更新其程式碼。
Java 和 Scala API 的統一
在 Spark 1.3 之前,有獨立的 Java 相容類別(JavaSQLContext
和 JavaSchemaRDD
),它們反映了 Scala API。在 Spark 1.3 中,Java API 和 Scala API 已統一。兩種語言的使用者都應該使用 SQLContext
和 DataFrame
。一般來說,這些類別會嘗試使用兩種語言都能使用的型別(例如 Array
,而不是特定語言的集合)。在某些不存在共用型別的情況下(例如,傳遞封閉或 Map),會改用函式重載。
此外,已移除 Java 特定的型別 API。Scala 和 Java 的使用者都應該使用 org.apache.spark.sql.types
中的類別,以透過程式描述架構。
隔離隱式轉換,並移除 dsl 套件(僅限 Scala)
在 Spark 1.3 之前的許多程式碼範例都從 import sqlContext._
開始,這會將 sqlContext 中的所有函式納入範圍。在 Spark 1.3 中,我們已將用於將 RDD
轉換為 DataFrame
的隱式轉換隔離到 SQLContext
內的物件中。使用者現在應該撰寫 import sqlContext.implicits._
。
此外,隱式轉換現在只會擴充由 Product
(例如,案例類別或元組)組成的 RDD,並使用 toDF
方法,而不是自動套用。
在 DSL 內使用函式時(現在已替換為 DataFrame
API),使用者會匯入 org.apache.spark.sql.catalyst.dsl
。改為使用公開的資料框函式 API:import org.apache.spark.sql.functions._
。
移除 org.apache.spark.sql 中 DataType 的型別別名(僅限 Scala)
Spark 1.3 移除 DataType
的基本 sql 套件中存在的型別別名。使用者改為匯入 org.apache.spark.sql.types
中的類別
UDF 註冊移至 sqlContext.udf
(Java 和 Scala)
用於註冊 UDF 的函式(用於 DataFrame DSL 或 SQL)已移至 SQLContext
中的 udf 物件。
sqlContext.udf.register("strLen", (s: String) => s.length())
sqlContext.udf().register("strLen", (String s) -> s.length(), DataTypes.IntegerType);
Python UDF 註冊保持不變。
與 Apache Hive 相容
Spark SQL 設計成與 Hive Metastore、SerDes 和 UDF 相容。目前,Hive SerDes 和 UDF 是基於內建的 Hive,而 Spark SQL 可以連接到不同版本的 Hive Metastore(從 0.12.0 到 2.3.9 和 3.0.0 到 3.1.3。另請參閱 與不同版本的 Hive Metastore 互動)。
在現有的 Hive 倉庫中部署
Spark SQL Thrift JDBC 伺服器設計成「開箱即用」,與現有的 Hive 安裝相容。您不需要修改現有的 Hive Metastore 或變更資料配置或資料表的分割。
支援的 Hive 功能
Spark SQL 支援絕大多數的 Hive 功能,例如
- Hive 查詢陳述式,包括
SELECT
GROUP BY
ORDER BY
DISTRIBUTE BY
CLUSTER BY
SORT BY
- 所有 Hive 運算子,包括
- 關係運算子(
=
、<=>
、==
、<>
、<
、>
、>=
、<=
等) - 算術運算子(
+
、-
、*
、/
、%
等) - 邏輯運算子(
AND
、OR
等) - 複雜型別建構函式
- 數學函式(
sign
、ln
、cos
等) - 字串函式(
instr
、length
、printf
等)
- 關係運算子(
- 使用者定義函式(UDF)
- 使用者定義聚合函式(UDAF)
- 使用者定義序列化格式(SerDes)
- 視窗函式
- 聯結
JOIN
{LEFT|RIGHT|FULL} OUTER JOIN
LEFT SEMI JOIN
LEFT ANTI JOIN
CROSS JOIN
- 聯集
- 子查詢
-
FROM 子句中的子查詢
SELECT col FROM (SELECT a + b AS col FROM t1) t2
-
WHERE 子句中的子查詢
-
WHERE 子句中相關或非相關的 IN 和 NOT IN 陳述式
SELECT col FROM t1 WHERE col IN (SELECT a FROM t2 WHERE t1.a = t2.a) SELECT col FROM t1 WHERE col IN (SELECT a FROM t2)
-
WHERE 子句中相關或非相關的 EXISTS 和 NOT EXISTS 陳述式
SELECT col FROM t1 WHERE EXISTS (SELECT t2.a FROM t2 WHERE t1.a = t2.a AND t2.a > 10) SELECT col FROM t1 WHERE EXISTS (SELECT t2.a FROM t2 WHERE t2.a > 10)
-
JOIN 條件中的非相關 IN 和 NOT IN 陳述式
SELECT t1.col FROM t1 JOIN t2 ON t1.a = t2.a AND t1.a IN (SELECT a FROM t3)
-
JOIN 條件中的非相關 EXISTS 和 NOT EXISTS 陳述式
SELECT t1.col FROM t1 JOIN t2 ON t1.a = t2.a AND EXISTS (SELECT * FROM t3 WHERE t3.a > 10)
-
-
- 抽樣
- 說明
- 包含動態區段插入的分區表格
- 檢視
-
如果檢視定義查詢中未指定欄位別名,Spark 和 Hive 都會產生別名名稱,但方式不同。為了讓 Spark 能夠讀取由 Hive 建立的檢視,使用者應在檢視定義查詢中明確指定欄位別名。例如,Spark 無法讀取由 Hive 建立如下所示的
v1
。CREATE VIEW v1 AS SELECT * FROM (SELECT c + 1 FROM (SELECT 1 c) t1) t2;
相反地,您應明確指定欄位別名,如下所示建立
v1
。CREATE VIEW v1 AS SELECT * FROM (SELECT c + 1 AS inc_c FROM (SELECT 1 c) t1) t2;
-
- 所有 Hive DDL 函數,包括
CREATE TABLE
CREATE TABLE AS SELECT
CREATE TABLE LIKE
ALTER TABLE
- 大多數 Hive 資料類型,包括
TINYINT
SMALLINT
INT
BIGINT
BOOLEAN
FLOAT
DOUBLE
STRING
BINARY
TIMESTAMP
DATE
ARRAY<>
MAP<>
STRUCT<>
不支援的 Hive 功能
以下是我們尚未支援的 Hive 功能清單。這些功能大多很少在 Hive 部署中使用。
深奧的 Hive 功能
UNION
類型- 唯一聯結
- 欄位統計資料收集:Spark SQL 目前不 piggyback 掃描來收集欄位統計資料,而且只支援填充 Hive metastore 的 sizeInBytes 欄位。
Hive 輸入/輸出格式
- CLI 的檔案格式:對於顯示回 CLI 的結果,Spark SQL 只支援 TextOutputFormat。
- Hadoop 存檔
Hive 最佳化
一些 Hive 最佳化尚未包含在 Spark 中。其中一些(例如索引)由於 Spark SQL 的記憶體中運算模式而較不重要。其他則已排定在 Spark SQL 的未來版本中發布。
- 區塊層級位元圖索引和虛擬欄位(用於建立索引)
- 自動判斷聯結和群組的還原器數量:目前,在 Spark SQL 中,您需要使用「
SET spark.sql.shuffle.partitions=[num_tasks];
」來控制後洗牌的並行度。 - 僅元資料查詢:對於僅使用元資料就能回答的查詢,Spark SQL 仍會啟動任務來運算結果。
- 傾斜資料標記:Spark SQL 沒有遵循 Hive 中的傾斜資料標記。
STREAMTABLE
聯結提示:Spark SQL 沒有遵循STREAMTABLE
提示。- 合併多個小檔案以取得查詢結果:如果結果輸出包含多個小檔案,Hive 可以選擇將小檔案合併成較少的大檔案,以避免 HDFS 元資料溢位。Spark SQL 不支援此功能。
Hive UDF/UDTF/UDAF
Spark SQL 不支援 Hive UDF/UDTF/UDAF 的所有 API。以下是未支援的 API
getRequiredJars
和getRequiredFiles
(UDF
和GenericUDF
) 是自動包含此 UDF 所需的其他資源的函式。initialize(StructObjectInspector)
在GenericUDTF
中尚未支援。Spark SQL 目前僅使用已棄用的介面initialize(ObjectInspector[])
。configure
(GenericUDF
、GenericUDTF
和GenericUDAFEvaluator
) 是使用MapredContext
初始化函式的函式,這不適用於 Spark。close
(GenericUDF
和GenericUDAFEvaluator
) 是釋放相關資源的函式。Spark SQL 在任務完成時不會呼叫此函式。reset
(GenericUDAFEvaluator
) 是重新初始化聚合以重複使用相同聚合的函式。Spark SQL 目前不支援重複使用聚合。getWindowingEvaluator
(GenericUDAFEvaluator
) 是透過評估固定視窗中的聚合來最佳化聚合的函式。
不相容的 Hive UDF
以下是 Hive 和 Spark 產生不同結果的場景
SQRT(n)
如果 n < 0,Hive 會傳回 null,Spark SQL 會傳回 NaN。ACOS(n)
如果 n < -1 或 n > 1,Hive 會傳回 null,Spark SQL 會傳回 NaN。ASIN(n)
如果 n < -1 或 n > 1,Hive 會傳回 null,Spark SQL 會傳回 NaN。CAST(n AS TIMESTAMP)
如果 n 是整數,Hive 會將 n 視為毫秒,Spark SQL 會將 n 視為秒數。