迁移指南:SQL、数据集和 DataFrame
- 从 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 Server 在取消正在运行的语句时会中断任务。要恢复之前的行为,请将
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 开始,对于格式错误的
str
输入,to_binary
函数会抛出错误。使用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 创建分区但其中一些分区已存在时,Spark 只会抛出
PartitionsAlreadyExistException
。在 Spark 3.3 或更早版本中,Spark 可以抛出PartitionsAlreadyExistException
或PartitionAlreadyExistsException
。 - 从 Spark 3.4 开始,Spark 将对 ALTER PARTITION 中的分区规范进行验证,以遵循
spark.sql.storeAssignmentPolicy
的行为,如果类型转换失败,这可能会导致异常,例如,如果列p
是 int 类型,则ALTER TABLE .. ADD PARTITION(p='a')
会导致异常。要恢复旧行为,请将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 中映射到 Arrow 的Duration
类型。此前,DayTimeIntervalType
映射到 Arrow 的Interval
类型,这与 Spark SQL 映射的其他语言的类型不匹配。例如,DayTimeIntervalType
在 Java 中映射到java.time.Duration
。 -
从 Spark 3.3 开始,函数
lpad
和rpad
已被重载以支持字节序列。当第一个参数是字节序列时,可选的填充模式也必须是字节序列,并且结果是 BINARY 值。在这种情况下,默认的填充模式是零字节。要恢复始终返回字符串类型的旧行为,请将spark.sql.legacy.lpadRpadAlwaysReturnString
设置为true
。 -
从 Spark 3.3 开始,当用户指定架构且架构包含不可为空的字段时,Spark 会针对 API
DataFrameReader.schema(schema: StructType).json(jsonDataset: Dataset[String])
和DataFrameReader.schema(schema: StructType).csv(csvDataset: Dataset[String])
将不可为空的架构转换为可为空的架构。要恢复遵循可空性的旧行为,请将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 开始,默认情况下,空值在 CSV 数据源中写入为空字符串。在 Spark 3.2 或更早版本中,空值被写成带引号的空字符串,即
""
。要恢复之前的行为,请将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 开始,类 round 函数的返回类型的精度已修复。这可能会导致 Spark 在使用先前版本创建的视图时抛出
CANNOT_UP_CAST_DATATYPE
错误类的AnalysisException
。在这种情况下,您需要使用较新版本的 Spark 通过 ALTER VIEW AS 或 CREATE OR REPLACE VIEW AS 重新创建视图。 -
从 Spark 3.3 开始,对于格式错误的
str
输入,unbase64
函数会抛出错误。使用try_to_binary(<str>, 'base64')
容忍格式错误的输入并返回 NULL。在 Spark 3.2 及更早版本中,对于格式错误的str
输入,unbase64
函数会返回尽力而为的结果。 -
从 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 不同。它的计算基于用户给定的 group-by 表达式加上分组集列。要恢复 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,并且不支持 MONEY[],因为 PostgreSQL 的 JDBC 驱动程序无法正确处理这些类型。在 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 中,对于来自 Hive external 的表,如果目标分区已存在,
ALTER TABLE .. RENAME TO PARTITION
会抛出PartitionAlreadyExistsException
而不是AnalysisException
。 -
在 Spark 3.2 中,对于无 serde 模式,脚本转换默认的 FIELD DELIMIT 为
\u0001
;对于 Hive serde 模式,当用户指定 serde 时,serde 属性field.delim
为\t
。在 Spark 3.1 或更早版本中,默认的 FIELD DELIMIT 为\t
,对于 Hive serde 模式,当用户指定 serde 时,serde 属性field.delim
为\u0001
。 -
在 Spark 3.2 中,自动生成的
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.*)
以避免产生歧义结果。因为如果存在任何空值,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'
,这是一个非法的日期值,我们最终会添加一个空值分区。 -
在 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 支持在 Hive
SERDE
模式下将DayTimeIntervalType
和YearMonthIntervalType
作为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 中,如果
LOCATION
不为空,则CREATE TABLE AS SELECT
将抛出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 中,如果将
allowMissingColumns
设置为 true,则Dataset.unionByName
会将缺少的嵌套字段添加到结构的末尾。在 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 中,当表达式求值过程中发生
DivideByZero
时(例如,将stddev_samp
应用于单个元素集时),统计聚合函数(包括std
、stddev
、stddev_samp
、variance
、var_samp
、skewness
、kurtosis
、covar_samp
、corr
)将返回NULL
,而不是Double.NaN
。在 Spark 3.0 及更早版本中,在这种情况下会返回Double.NaN
。要恢复到 Spark 3.1 之前的行为,您可以将spark.sql.legacy.statisticalAggregate
设置为true
。 -
在 Spark 3.1 中,grouping_id() 返回 long 值。在 Spark 3.0 及更早版本中,此函数返回 int 值。要恢复到 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 时,如果 decimal 类型列的总和溢出,Spark 始终返回 null。在 Spark 3.0 或更早版本中,在这种情况下,decimal 类型列的总和可能会返回 null 或错误结果,甚至在运行时失败(取决于实际的查询计划执行)。 -
在 Spark 3.1 中,当使用路径参数调用以下方法时,
path
选项不能共存:DataFrameReader.load()
、DataFrameWriter.save()
、DataStreamReader.load()
或DataStreamWriter.start()
。此外,对于DataFrameReader.load()
,paths
选项不能共存。例如,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 中,在以下情况下,对于来自 Hive 外部目录的表,
AnalysisException
被其子类替换,这些子类在以下情况下抛出- 如果新分区已存在,则
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 选项
timestampFormat
定义的模式匹配,则 JSON 数据源和 JSON 函数schema_of_json
会从字符串值推断出 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
数据集/DataFrame API
-
在 Spark 3.0 中,Dataset 和 DataFrame API
unionAll
已弃用。它是union
的别名。 -
在 Spark 2.4 及更低版本中,如果键是非结构类型(例如 int、string、array 等),则
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)
。 -
将 Dataset 转换为另一个 Dataset 时,Spark 会将原始 Dataset 中的字段向上转换为目标 Dataset 中相应字段的类型。在 2.4 及更早版本中,这种向上转换不是很严格,例如
Seq("str").toDS.as[Int]
会失败,但Seq("str").toDS.as[Boolean]
可以工作并在执行期间抛出 NPE。在 Spark 3.0 中,向上转换更加严格,不允许将 String 转换为其他类型,即Seq("str").toDS.as[Boolean]
在分析期间会失败。要恢复到 Spark 3.0 之前的行为,请将spark.sql.legacy.doLooseUpcast
设置为true
。
DDL 语句
-
在 Spark 3.0 中,将值插入到具有不同数据类型的表列时,将按照 ANSI SQL 标准执行类型强制转换。不允许某些不合理的类型转换,例如将
string
转换为int
和将double
转换为boolean
。如果该值超出了列数据类型的范围,则会抛出运行时异常。在 Spark 2.4 及更低版本中,只要类型转换是有效的Cast
,就允许在表插入期间进行类型转换。将超出范围的值插入到整数字段时,将插入该值的低位(与 Java/Scala 数值类型转换相同)。例如,如果将 257 插入到 byte 类型的字段中,则结果为 1。此行为由选项spark.sql.storeAssignmentPolicy
控制,默认值为“ANSI”。将该选项设置为“Legacy”将恢复之前的行为。 -
ADD JAR
命令以前返回一个包含单个值 0 的结果集。现在它返回一个空的结果集。 -
Spark 2.4 及更低版本:即使指定的键用于
SparkConf
条目,SET
命令也可以正常工作,并且没有任何警告,因为它不会更新SparkConf
,但这可能会使用户感到困惑。在 3.0 中,如果使用SparkConf
键,则该命令将失败。您可以通过将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 记录时。例如,具有架构a INT
的 JSON 字符串{"a" 1}
被以前的版本转换为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 函数(包括相关的 SQL 函数,如LOG10
)的结果返回值与java.lang.StrictMath
一致。在几乎所有情况下,这对返回值没有影响,并且差异非常小,但在某些情况下(例如,log(3.0)
,其值在Math.log()
和StrictMath.log()
之间变化)可能与 x86 平台上的java.lang.Math
不完全匹配。 -
在 Spark 3.0 中,
cast
函数在将字符串字面量转换为Double
或Float
类型时,以不区分大小写的方式处理字符串字面量,例如“Infinity”、“+Infinity”、“-Infinity”、“NaN”、“Inf”、“+Inf”、“-Inf”,以确保与其他数据库系统更好地兼容。此行为更改如下表所示操作 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 中,将间隔值转换为字符串类型时,没有“interval”前缀,例如,
1 days 2 hours
。在 Spark 2.4 及更早版本中,字符串包含“interval”前缀,如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 中,一元算术运算符加号 (
+
) 仅接受字符串、数字和间隔类型值作为输入。此外,带有整数字符串表示形式的+
会被强制转换为 double 值,例如,+'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 及更早版本中,浮点数/双精度数 -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 及更早版本中,无效的时区 ID 会被静默忽略,并替换为 GMT 时区,例如在 from_utc_timestamp 函数中。在 Spark 3.0 中,此类时区 ID 会被拒绝,Spark 会抛出
java.time.DateTimeException
。 -
在 Spark 3.0 中,Proleptic Gregorian 日历用于解析、格式化和转换日期和时间戳,以及提取年份、日期等子组件。Spark 3.0 使用
java.time
包中的 Java 8 API 类,这些类基于 ISO 年表。在 Spark 2.4 及更早版本中,这些操作使用混合日历(儒略历 + 格里高利历)执行。这些更改会影响 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 日历和 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 中,使用 SQL 配置
spark.sql.session.timeZone
将TIMESTAMP
字面量转换为字符串。在 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 系统时间零点)today [zoneId]
- 今天午夜yesterday [zoneId]
- 昨天午夜tomorrow [zoneId]
- 明天午夜now
- 当前查询开始时间
例如,
SELECT timestamp 'tomorrow';
。 -
从 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 将尝试使用内置数据源写入器而不是 Hive Serde 来处理
CTAS
。仅当分别为 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 表中。仅当分别为 Parquet 和 ORC 格式启用了
spark.sql.hive.convertMetastoreParquet
或spark.sql.hive.convertMetastoreOrc
时,此行为才有效。要恢复 Spark 3.0 之前的行为,可以将spark.sql.hive.convertInsertingPartitionedTable
设置为false
。
数据源
-
在 Spark 2.4 及更早版本中,当使用 Spark 本机数据源(parquet/orc)读取 Hive SerDe 表时,Spark 会推断实际文件架构并更新元存储中的表架构。在 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 数据源的解析器会将空字符串视为某些数据类型的 null,例如
IntegerType
。对于FloatType
、DoubleType
、DateType
和TimestampType
,它无法处理空字符串并抛出异常。Spark 3.0 不允许空字符串,并且会为除StringType
和BinaryType
之外的所有数据类型抛出异常。可以通过将spark.sql.legacy.json.allowEmptyString.enabled
设置为true
来恢复允许空字符串的先前行为。 -
在 Spark 2.4 及更早版本中,当指定架构为
StructType
时,JSON 数据源和 JSON 函数(如from_json
)会在 PERMISSIVE 模式下将错误的 JSON 记录转换为所有字段均为null
的行。在 Spark 3.0 中,如果某些 JSON 列值已成功解析并转换为所需类型,则返回的行可以包含非null
字段。 -
在 Spark 3.0 中,如果字符串值与 JSON 选项
timestampFormat
定义的模式匹配,则 JSON 数据源和 JSON 函数schema_of_json
会从字符串值推断 TimestampType。将 JSON 选项inferTimestamp
设置为false
可禁用此类类型推断。 -
在 Spark 2.4 及更早版本中,CSV 数据源会在 PERMISSIVE 模式下将格式错误的 CSV 字符串转换为所有字段均为
null
的行。在 Spark 3.0 中,如果某些 CSV 列值已成功解析并转换为所需类型,则返回的行可以包含非null
字段。 -
在 Spark 3.0 中,使用用户提供的架构写入 Avro 文件时,字段将通过 Catalyst 架构和 Avro 架构之间的字段名称而不是位置进行匹配。
-
在 Spark 3.0 中,使用用户提供的不可为空的架构写入 Avro 文件时,即使 Catalyst 架构可以为空,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
,这将回退到 3.0 之前的 Spark 版本中的编码自动检测。
其他
-
在 Spark 2.4 中,当通过
cloneSession()
创建 Spark 会话时,新创建的 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 元存储的版本设置
spark.sql.hive.metastore.version
和spark.sql.hive.metastore.jars
。例如:如果您的 Hive 元存储版本为 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 中,
spark.executor.heartbeatInterval
的值(如果在指定时没有使用“30s”之类的单位,而是使用“30”)在代码的不同部分中被不一致地解释为秒和毫秒。现在,无单位值始终被解释为毫秒。设置了“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 中,左参数和右参数分别提升为双精度浮点型数组类型和双精度浮点型。 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 会在将 DATE 类型和 TIMESTAMP 类型都提升为 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 表时会 respetar 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-?'
。特殊字符(如空格
)现在也可以在路径中使用。示例: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 元存储架构和 Parquet 架构中列名大小写不同的任何列,Spark 始终返回 null,无论
spark.sql.caseSensitive
是设置为true
还是false
。从 2.4 开始,当spark.sql.caseSensitive
设置为false
时,Spark 会在 Hive 元存储架构和 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 DateType TimestampType StringType
</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)。这涉及以下更改
-
用于确定算术运算结果类型的规则已更新。特别是,如果所需的精度/比例超出了可用值的范围,则比例将减少到 6,以防止截断小数的整数部分。所有算术运算都会受到更改的影响,即加法 (
+
)、减法 (-
)、乘法 (*
)、除法 (/
)、余数 (%
) 和正模数 (pmod
)。 -
SQL 操作中使用的字面量将转换为具有所需精确精度和比例的 DECIMAL。
-
引入了配置
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 元存储表的兼容性,这些表的底层文件架构具有混合大小写的列名。使用INFER_AND_SAVE
配置值,在第一次访问时,Spark 将对尚未保存推断架构的任何 Hive 元存储表执行架构推断。请注意,对于具有数千个分区的表,架构推断可能是一项非常耗时的操作。如果不关心与混合大小写列名的兼容性,可以安全地将spark.sql.hive.caseSensitiveInferenceMode
设置为NEVER_INFER
,以避免架构推断的初始开销。请注意,使用新的默认INFER_AND_SAVE
设置,架构推断的结果将保存为元存储键以供将来使用。因此,初始架构推断仅在第一次访问表时发生。 -
从 Spark 2.2.1 和 2.3.0 开始,当数据源表在分区架构和数据架构中都存在列时,架构总是在运行时推断。推断的架构没有分区列。读取表时,Spark 会 respetar 这些重叠列的分区值,而不是存储在数据源文件中的值。在 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 元存储中。这意味着 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 将保留以实现向后兼容性。可以通过SparkSession
访问新的catalog
接口 - 数据库和表访问的现有 API(例如listTables
、createExternalTable
、dropTempView
、cacheTable
)已移至此处。 -
Dataset API 和 DataFrame API 已统一。在 Scala 中,
DataFrame
成为Dataset[Row]
的类型别名,而 Java API 用户必须将DataFrame
替换为Dataset<Row>
。类型化转换(例如,map
、filter
和groupByKey
)和非类型化转换(例如,select
和groupBy
)都可以在 Dataset 类上使用。由于 Python 和 R 中的编译时类型安全不是语言特性,因此 Dataset 的概念不适用于这些语言的 API。相反,DataFrame
仍然是主要的编程抽象,它类似于这些语言中的单节点数据帧概念。 -
Dataset 和 DataFrame API
unionAll
已弃用,并替换为union
-
Dataset 和 DataFrame API
explode
已弃用,或者,将functions.explode()
与select
或flatMap
一起使用 -
Dataset 和 DataFrame API
registerTempTable
已弃用,并替换为createOrReplaceTempView
-
Hive 表的
CREATE TABLE ... LOCATION
行为的更改。-
从 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
- 从 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)
。 -
现在以 1 微秒的精度存储时间戳,而不是 1 纳秒
-
在
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
。
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 系列中其他版本的二进制兼容性。此兼容性保证不包括明确标记为不稳定(即 DeveloperAPI 或 Experimental)的 API。
将 SchemaRDD 重命名为 DataFrame
用户在升级到 Spark SQL 1.3 时会注意到的最大变化是 SchemaRDD
已重命名为 DataFrame
。这主要是因为 DataFrame 不再直接继承自 RDD,而是通过自身的实现提供了 RDD 提供的大部分功能。仍然可以通过调用 .rdd
方法将 DataFrame 转换为 RDD。
在 Scala 中,有一个从 SchemaRDD
到 DataFrame
的类型别名,以便为某些用例提供源代码兼容性。仍然建议用户更新其代码以使用 DataFrame
。
Java 和 Scala API 的统一
在 Spark 1.3 之前,有单独的 Java 兼容类(JavaSQLContext
和 JavaSchemaRDD
)来镜像 Scala API。在 Spark 1.3 中,Java API 和 Scala API 已经统一。两种语言的用户都应该使用 SQLContext
和 DataFrame
。通常,这些类尝试使用两种语言都可以使用的类型(例如,使用 Array
而不是特定于语言的集合)。在某些情况下,如果不存在通用类型(例如,用于传入闭包或映射),则改用函数重载。
此外,特定于 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
(即 case 类或元组)组成的 RDD 中添加一个方法 toDF
,而不是自动应用。
当在 DSL(现在已替换为 DataFrame
API)中使用函数时,用户过去常常导入 org.apache.spark.sql.catalyst.dsl
。现在应该使用公共 dataframe 函数 API:import org.apache.spark.sql.functions._
。
删除 org.apache.spark.sql 中 DataType 的类型别名(仅限 Scala)
Spark 1.3 删除了基本 sql 包中 DataType
的类型别名。用户应该改为导入 org.apache.spark.sql.types
中的类
UDF 注册移至 sqlContext.udf
(Java 和 Scala)
用于注册 UDF 的函数(无论是在 DataFrame DSL 还是 SQL 中使用)都已移至 SQLContext
中的 udf 对象中。
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 语句
从 t1 表中选择 t1.col 列,将 t1 与 t2 表连接,连接条件为 t1.a 等于 t2.a,并且存在于 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 目前不支持搭载扫描来收集列统计信息,仅支持填充 hive 元存储的 sizeInBytes 字段。
Hive 输入/输出格式
- CLI 的文件格式:对于显示回 CLI 的结果,Spark SQL 仅支持 TextOutputFormat。
- Hadoop 存档
Hive 优化
Spark 中尚未包含少数 Hive 优化。由于 Spark SQL 的内存计算模型,其中一些(例如索引)不太重要。其他一些计划用于未来版本的 Spark SQL。
- 块级位图索引和虚拟列(用于构建索引)
- 自动确定连接和分组的 reducer 数量:目前,在 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 所需的其他资源的函数。GenericUDTF
中的initialize(StructObjectInspector)
尚不支持。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 视为秒。