迁移指南:SQL、Datasets 和 DataFrame
- 从 Spark SQL 3.5.3 升级到 3.5.4
- 从 Spark SQL 3.5.1 升级到 3.5.2
- 从 Spark SQL 3.5.0 升级到 3.5.1
- 从 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.5.3 升级到 3.5.4
- 从 Spark 3.5.4 开始,当读取 SQL 表时遇到
org.apache.hadoop.security.AccessControlException
和org.apache.hadoop.hdfs.BlockMissingException
异常时,即使spark.sql.files.ignoreCorruptFiles
设置为true
,也会抛出异常并导致任务失败。
从 Spark SQL 3.5.1 升级到 3.5.2
- 从 3.5.2 开始,MySQL JDBC 数据源会将 TINYINT UNSIGNED 读取为 ShortType,而在 3.5.1 中,它被错误地读取为 ByteType。
从 Spark SQL 3.5.0 升级到 3.5.1
- 从 Spark 3.5.1 开始,MySQL JDBC 数据源会将 TINYINT(n > 1) 和 TINYINT UNSIGNED 读取为 ByteType,而在 Spark 3.5.0 及更早版本中,它们被读取为 IntegerType。要恢复之前的行为,您可以将该列强制转换为旧类型。
从 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 起,
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 创建分区但其中一些分区已存在时,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 起,默认启用 Bloom 过滤器连接。 要恢复旧的行为,请将
spark.sql.optimizer.runtime.bloomFilter.enabled
设置为false
。 - 自 Spark 3.4 起,当对外部 Parquet 文件进行模式推断时,带有注释
isAdjustedToUTC=false
的 INT64 时间戳将被推断为 TimestampNTZ 类型,而不是 Timestamp 类型。 要恢复旧的行为,请将spark.sql.parquet.inferTimestampNTZ.enabled
设置为false
。 - 自 Spark 3.4 起,当
spark.sql.legacy.allowNonEmptyLocationInCTAS
设置为true
时,CREATE TABLE AS SELECT ...
的行为将从 OVERWRITE 更改为 APPEND。 建议用户避免使用具有非空表位置的 CTAS。
从 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
被映射到 Arrow 的Interval
类型,这与其他 Spark SQL 映射的语言的类型不匹配。例如,DayTimeIntervalType
在 Java 中被映射到java.time.Duration
。 -
从 Spark 3.3 开始,函数
lpad
和rpad
进行了重载以支持字节序列。当第一个参数是字节序列时,可选的填充模式也必须是字节序列,结果是一个 BINARY 值。 在这种情况下,默认的填充模式是零字节。要恢复始终返回字符串类型的旧行为,请将spark.sql.legacy.lpadRpadAlwaysReturnString
设置为true
。 -
从 Spark 3.3 开始,当用户指定的 schema 包含非空字段时,Spark 会将 API
DataFrameReader.schema(schema: StructType).json(jsonDataset: Dataset[String])
和DataFrameReader.schema(schema: StructType).csv(csvDataset: Dataset[String])
的非空 schema 转换为可空 schema。要恢复保留 nullability 的旧行为,请将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 数据源中的 null 值被写为空字符串。 在 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"
和"-Infinity"
变体之外,字符串"+Infinity"
、"+INF"
和"-INF"
现在被解析为适当的值。 进行此更改是为了提高与 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 开始,
unbase64
函数会为格式错误的str
输入抛出错误。 使用try_to_binary(<str>, 'base64')
来容忍格式错误的输入并返回 NULL。 在 Spark 3.2 及更早版本中,unbase64
函数会为格式错误的str
输入返回尽力而为的结果。 -
从 Spark 3.3 开始,读取非 Spark 生成的 Parquet 文件时,带有注释
isAdjustedToUTC = false
的 Parquet 时间戳列在 schema 推断期间被推断为 TIMESTAMP_NTZ 类型。 在 Spark 3.2 及更早版本中,这些列被推断为 TIMESTAMP 类型。 要恢复 Spark 3.3 之前的行为,可以将spark.sql.parquet.inferTimestampNTZ.enabled
设置为false
。 -
自 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 表达式加上 grouping set 列进行计算。 要恢复 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 中,当目标分区已存在时,对于来自 Hive 外部的表,
ALTER TABLE .. RENAME TO PARTITION
会抛出PartitionAlreadyExistsException
而不是AnalysisException
。 -
在 Spark 3.2 中,对于 no serde 模式,脚本转换的默认 FIELD DELIMIT 为
\u0001
,当用户指定 serde 时,Hive serde 模式的 serde 属性field.delim
为\t
。 在 Spark 3.1 或更早版本中,默认 FIELD DELIMIT 为\t
,当用户指定 serde 时,Hive 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
的输出 schema 变为namespace: string, tableName: string, isTemporary: boolean
。 在 Spark 3.1 或更早版本中,对于内置目录,namespace
字段被命名为database
,并且对于 v2 目录,没有isTemporary
字段。 要恢复具有内置目录的旧 schema,可以将spark.sql.legacy.keepCommandOutputSchema
设置为true
。 -
在 Spark 3.2 中,
SHOW TABLE EXTENDED
的输出 schema 变为namespace: string, tableName: string, isTemporary: boolean, information: string
。 在 Spark 3.1 或更早版本中,对于内置目录,namespace
字段被命名为database
,对于 v2 目录没有更改。 要恢复具有内置目录的旧 schema,可以将spark.sql.legacy.keepCommandOutputSchema
设置为true
。 -
在 Spark 3.2 中,无论是否指定表属性键,
SHOW TBLPROPERTIES
的输出模式都变为key: string, value: string
。在 Spark 3.1 及更早版本中,当您指定表属性键时,SHOW TBLPROPERTIES
的输出模式为value: string
。要使用内置 catalog 恢复旧模式,您可以将spark.sql.legacy.keepCommandOutputSchema
设置为true
。 -
在 Spark 3.2 中,
DESCRIBE NAMESPACE
的输出模式变为info_name: string, info_value: string
。在 Spark 3.1 或更早版本中,对于内置 catalog,info_name
字段名为database_description_item
,info_value
字段名为database_description_value
。要使用内置 catalog 恢复旧模式,您可以将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 支持将
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 中,使用非空
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
,默认情况下它是 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 中,统计聚合函数包括
std
,stddev
,stddev_samp
,variance
,var_samp
,skewness
,kurtosis
,covar_samp
,corr
,当表达式计算过程中发生DivideByZero
错误时,例如,当stddev_samp
应用于单个元素集合时,将返回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 中,如果指定的 datetime 模式无效,
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 中,structs 和 maps 在转换为字符串时,会使用
{}
括号括起来。 例如,show()
操作和CAST
表达式使用此类括号。 在 Spark 3.0 及更早版本中,[]
括号用于相同的目的。 要恢复 Spark 3.1 之前的行为,您可以将spark.sql.legacy.castComplexTypesToString.enabled
设置为true
。 -
在 Spark 3.1 中,structures、arrays 和 maps 的 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()
。 此外,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 字面量,例如
INTERVAL '1'
、INTERVAL '1 DAY 2'
(无效),会返回IllegalArgumentException
。 在 Spark 3.0 中,这些字面量会导致NULL
s。 -
在 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 中,该操作不会失败,但由于从/向 Julian 日历到/从 Proleptic Gregorian 日历的重新基准化,可能会导致输入时间戳的偏移。 要恢复 Spark 3.1 之前的行为,您可以将
spark.sql.legacy.parquet.int96RebaseModeInRead
和/或spark.sql.legacy.parquet.int96RebaseModeInWrite
设置为LEGACY
。 -
在 Spark 3.1 中,
schema_of_json
和schema_of_csv
函数返回 SQL 格式的 schema,其中字段名称被引用。 在 Spark 3.0 中,该函数返回一个目录字符串,其中没有字段引用并且是小写的。 -
在 Spark 3.1 中,刷新表将触发对引用该表的所有其他缓存(即使该表本身未被缓存)的 uncache 操作。 在 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 以来,表 schema 中支持 CHAR/CHARACTER 和 VARCHAR 类型。 表扫描/插入将遵守 char/varchar 语义。 如果 char/varchar 用于表 schema 以外的位置,则将抛出异常(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 中,对于 Hive 外部目录中的表,在以下情况下,
AnalysisException
被其子类替换。- 如果新分区已存在,
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
的输出 schema 变为namespace: string
。 在 Spark 3.0.1 及更早版本中,schema 为databaseName: string
。 从 Spark 3.0.2 开始,您可以通过将spark.sql.legacy.keepCommandOutputSchema
设置为true
来恢复旧的 schema。
从 Spark SQL 3.0 升级到 3.0.1
-
在 Spark 3.0 中,JSON 数据源和 JSON 函数
schema_of_json
从字符串值推断 TimestampType,如果它们与 JSON 选项timestampFormat
定义的模式匹配。 从 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 APIs
-
在 Spark 3.0 中,Dataset 和 DataFrame API
unionAll
不再被弃用。 它是union
的别名。 -
在 Spark 2.4 及以下版本中,如果键是非结构类型(例如,int、string、array 等),则
Dataset.groupByKey
导致分组数据集的键属性错误地命名为 “value”。 这是违反直觉的,并使聚合查询的 schema 变得出乎意料。 例如,ds.groupByKey(...).count()
的 schema 是(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 类型,并且长度参数将被简单地忽略。
UDFs 和内置函数
-
在 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 记录时。例如,带有 schemaa INT
的 JSON 字符串{"a" 1}
在以前的版本中被转换为null
,但 Spark 3.0 将其转换为Row(null)
。 -
在 Spark 2.4 及以下版本中,您可以使用内置函数(例如
CreateMap
,MapFromArrays
等)创建带有 map 类型键的 map 值。在 Spark 3.0 中,不允许使用这些内置函数创建带有 map 类型键的 map 值。用户可以使用map_entries
函数将 map 转换为 array<struct<key, value» 作为解决方法。此外,用户仍然可以从数据源或 Java/Scala 集合中读取带有 map 类型键的 map 值,尽管不鼓励这样做。 -
在 Spark 2.4 及以下版本中,您可以通过内置函数(例如
CreateMap
,StringToMap
等)创建具有重复键的 map。具有重复键的 map 的行为是未定义的,例如,map 查找尊重首先出现的重复键,Dataset.collect
仅保留最后出现的重复键,MapKeys
返回重复键等。在 Spark 3.0 中,当找到重复键时,Spark 会抛出RuntimeException
。您可以将spark.sql.mapKeyDedupPolicy
设置为LAST_WIN
,以使用后胜出策略来删除 map 键中的重复项。用户仍然可以从不强制执行此策略的数据源(例如,Parquet)读取具有重复键的 map 值,但其行为是未定义的。 -
在 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)
,如果 columnx
为 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 在 executor 端执行,与其他 UDF 的执行方式相同。在 Spark 2.4 及更早版本中,只有 0 参数的 Java UDF 在 driver 端执行,结果传播到 executors,这在某些情况下可能更高效,但在某些情况下会导致正确性问题不一致。
-
java.lang.Math
的log
、log1p
、exp
、expm1
和pow
的结果可能因平台而异。在 Spark 3.0 中,等效的 SQL 函数(包括相关的 SQL 函数,如LOG10
)返回与java.lang.StrictMath
一致的值。在几乎所有情况下,这都不会对返回值产生影响,并且差异非常小,但在某些情况下,例如log(3.0)
,可能与 x86 平台上的java.lang.Math
不完全匹配,其值在Math.log()
和StrictMath.log()
之间变化。 -
在 Spark 3.0 中,
cast
函数在将字符串字面量(如 ‘Infinity’、‘+Infinity’、‘-Infinity’、‘NaN’、‘Inf’、‘+Inf’、‘-Inf’)转换为Double
或Float
类型时,以不区分大小写的方式处理这些字面量,以确保与其他数据库系统具有更好的兼容性。下表说明了此行为更改操作 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 值转换为 string 类型时,没有 “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 及更早版本中,SQL 查询(例如
FROM <table>
或FROM <table> UNION ALL FROM <table>
)由于偶然原因而受支持。在 hive 风格的FROM <table> SELECT <expr>
中,SELECT
子句不可忽略。Hive 和 Presto 都不支持此语法。这些查询在 Spark 3.0 中被视为无效。 -
在 Spark 3.0 中,interval 字面量语法不再允许多个 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 中,日-时 interval 字符串根据
from
和to
边界转换为 intervals。如果输入字符串与指定边界定义的模式不匹配,则会抛出ParseException
异常。例如,interval '2 10:20' hour to minute
会引发异常,因为预期格式为[+|-]h[h]:[m]m
。在 Spark 2.4 版本中,没有考虑from
边界,并且to
边界用于截断结果 interval。例如,上面示例中的日-时 interval 字符串被转换为interval 10 hours 20 minutes
。要恢复 Spark 3.0 之前的行为,可以将spark.sql.legacy.fromDayTimeString.enabled
设置为true
。 -
在 Spark 3.0 中,默认情况下不允许 decimal 的负 scale,例如,字面量(如
1E10BD
)的数据类型为DecimalType(11, 0)
。在 Spark 2.4 及更早版本中,它是DecimalType(2, -9)
。要恢复 Spark 3.0 之前的行为,可以将spark.sql.legacy.allowNegativeScaleOfDecimal
设置为true
。 -
在 Spark 3.0 中,一元算术运算符加号(
+
)仅接受字符串、数字和 interval 类型的值作为输入。此外,具有整数字符串表示形式的+
被强制转换为 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 列引用,并且在 Spark 中,df1("a")
与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 及更早版本中,无效的时区 ID 会被静默忽略,并替换为 GMT 时区,例如,在 from_utc_timestamp 函数中。在 Spark 3.0 中,此类时区 ID 会被拒绝,并且 Spark 抛出
java.time.DateTimeException
。 -
在 Spark 3.0 中,在解析、格式化和转换日期和时间戳以及提取年份、天数等子组件时,使用普罗列公历。Spark 3.0 使用 ISO 时序 的
java.time
包中的 Java 8 API 类。在 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 值。转换基于普罗列公历,以及由 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
- 运行当前查询的日期。它与今天具有相同的概念
例如
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 及以下版本中,JSON 数据源和 JSON 函数(如
from_json
)在 PERMISSIVE 模式下,当指定的 schema 是StructType
时,会将错误的 JSON 记录转换为所有null
的行。在 Spark 3.0 中,如果某些 JSON 列值已成功解析并转换为所需的类型,则返回的行可以包含非null
字段。 -
在 Spark 3.0 中,如果 JSON 数据源和 JSON 函数
schema_of_json
中的字符串值符合 JSON 选项timestampFormat
定义的模式,则会推断出 TimestampType 类型。将 JSON 选项inferTimestamp
设置为false
可禁用此类类型推断。 -
在 Spark 2.4 及更早版本中,CSV 数据源会将格式错误的 CSV 字符串转换为一行,该行的所有字段在 PERMISSIVE 模式下均为
null
。在 Spark 3.0 中,如果某些 CSV 列值已成功解析并转换为所需的类型,则返回的行可能包含非null
字段。 -
在 Spark 3.0 中,当使用用户提供的 schema 写入 Avro 文件时,字段会通过 Catalyst schema 和 Avro schema 之间的字段名称进行匹配,而不是通过位置进行匹配。
-
在 Spark 3.0 中,当使用用户提供的非空 schema 写入 Avro 文件时,即使 Catalyst schema 允许为空,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 版本中,当通过
cloneSession()
创建 Spark 会话时,新创建的 Spark 会话会从其父SparkContext
继承其配置,即使父 Spark 会话中存在具有不同值的相同配置。在 Spark 3.0 中,父SparkSession
的配置优先级高于父SparkContext
。您可以通过将spark.sql.legacy.sessionInitWithConfigDefaults
设置为true
来恢复旧的行为。 -
在 Spark 3.0 中,如果在
Spark SQL configuration
中未找到hive.default.fileformat
,则会回退到SparkContext
的Hadoop configuration
中存在的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
profile 构建自己的 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 Guide,MsSQLServer JDBC Dialect 分别对 SMALLINT 和 REAL 使用 ShortType 和 FloatType。以前,使用 IntegerType 和 DoubleType。
从 Spark SQL 2.4 升级到 2.4.1
- 当未指定单位(如“30”而不是“30s”)时,
spark.executor.heartbeatInterval
的值在 Spark 2.4.0 的代码的不同部分中被不一致地解释为秒和毫秒。现在,无单位的值始终被解释为毫秒。现在,设置了诸如“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 中,左侧和右侧参数分别提升为 double 类型的数组类型和 double 类型。 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 运算符前面有一个 struct 字段时,内部查询也必须包含一个 struct 字段。在以前的版本中,struct 的字段与内部查询的输出进行比较。例如,如果
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 起,即使在物理上 dataframe 没有分区,将空 dataframe 写入目录也会启动至少一项写入任务。这引入了一个小的行为更改,即对于像 Parquet 和 Orc 这样的自描述文件格式,Spark 在写入 0 分区 dataframe 时会在目标目录中创建一个仅包含元数据的文件,这样,如果用户稍后读取该目录,schema 推断仍然可以工作。关于写入空 dataframe,新行为更合理且更一致。
-
自 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 等)写入具有空或嵌套空 schema 的 dataframe。尝试写入具有空 schema 的 dataframe 时会抛出异常。
-
从 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 表时会遵守 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 行被视为格式错误。 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 数据源表读取数据时,无论
spark.sql.caseSensitive
设置为true
还是false
,对于 Hive metastore 模式和 Parquet 模式中的列名大小写不同的任何列,Spark 始终返回 null。 从 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
函数之前接受数字类型输入并输出 double 类型结果。 现在它支持日期类型、时间戳类型和数字类型作为输入类型。 结果类型也已更改为与输入类型相同,这对于百分位数更合理。 -
从 Spark 2.3 开始,如果可能,也会将第一个非确定性谓词之后的 Join/Filter 的确定性谓词下推/穿过子运算符。 在之前的 Spark 版本中,这些过滤器不符合谓词下推的条件。
-
分区列推断之前为不同的推断类型找到了不正确的通用类型,例如,之前它以 double 类型作为 double 类型和日期类型的通用类型结束。 现在,它为这种冲突找到了正确的通用类型。 冲突解决遵循下表
输入A \ 输入B NullType IntegerType LongType DecimalType(38,0)* DoubleType DateType TimestampType StringType NullType NullType IntegerType LongType DecimalType(38,0) DoubleType DateType TimestampType StringType IntegerType IntegerType IntegerType LongType DecimalType(38,0) DoubleType StringType StringType StringType LongType LongType LongType LongType DecimalType(38,0) StringType StringType StringType StringType DecimalType(38,0)* DecimalType(38,0) DecimalType(38,0) DecimalType(38,0) DecimalType(38,0) StringType StringType StringType StringType DoubleType DoubleType DoubleType StringType StringType DoubleType StringType StringType StringType DateType DateType StringType StringType StringType StringType DateType TimestampType StringType TimestampType TimestampType StringType StringType StringType StringType TimestampType TimestampType StringType StringType StringType StringType StringType StringType StringType StringType StringType StringType 请注意,对于 DecimalType(38,0)*,上表有意不涵盖所有其他比例和精度的组合,因为目前我们只推断像
BigInteger
/BigInt
这样的 decimal 类型。 例如,1.1 被推断为 double 类型。 -
从 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 的新行为 (HIVE-15331)。 这涉及以下更改
-
用于确定算术运算结果类型的规则已更新。 特别是,如果所需的精度/比例超出可用值的范围,则比例最多会减少到 6,以防止截断小数的整数部分。 所有算术运算都受到此更改的影响,即加法 (
+
)、减法 (-
)、乘法 (*
)、除法 (/
)、余数 (%
) 和正模 (pmod
)。 -
SQL 操作中使用的文字值会转换为 DECIMAL,其精度和比例由它们的需求决定。
-
引入了配置项
spark.sql.decimalOperations.allowPrecisionLoss
。它的默认值为true
,这意味着此处描述的新行为;如果设置为false
,Spark 将使用之前的规则,即它不会调整所需的 scale 以表示值,如果无法精确表示该值,则返回 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 尊重这些重叠列的分区值,而不是存储在数据源文件中的值。在 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 表的行为不同,Hive 表的行为是仅覆盖与新插入的数据重叠的分区。
-
从 Spark SQL 1.6 升级到 2.0
-
SparkSession
现在是 Spark 的新入口点,它取代了旧的SQLContext
和HiveContext
。请注意,为了向后兼容,保留了旧的 SQLContext 和 HiveContext。可以通过SparkSession
访问一个新的catalog
接口 - 诸如listTables
,createExternalTable
,dropTempView
,cacheTable
之类的数据库和表访问的现有 API 已移动到此处。 -
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
。
./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
的 API 文档(Scala,Java,Python)和 DataFrame.write
的 API 文档(Scala,Java,Python)。
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
中存在的类来以编程方式描述 schema。
隐式转换的隔离和 dsl 包的删除(仅限 Scala)
Spark 1.3 之前的许多代码示例都以 import sqlContext._
开头,这将 sqlContext 中的所有函数都引入了作用域。在 Spark 1.3 中,我们已将用于将 RDD
转换为 DataFrame
的隐式转换隔离到 SQLContext
中的一个对象内部。用户现在应该编写 import sqlContext.implicits._
。
此外,隐式转换现在仅使用方法 toDF
来扩充由 Product
(即,case 类或元组)组成的 RDD,而不是自动应用。
当使用 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 对象中。
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 或更改表的data placement 或分区。
支持的 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
- Unions
- 子查询
-
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)
-
-
- 采样
- Explain
- 分区表,包括动态分区插入
- 视图
-
如果在视图定义查询中未指定列别名,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
类型- Unique join
- 列统计信息收集:Spark SQL 目前不 piggyback 扫描来收集列统计信息,并且仅支持填充 hive metastore 的 sizeInBytes 字段。
Hive 输入/输出格式
- CLI 的文件格式:对于显示回 CLI 的结果,Spark SQL 仅支持 TextOutputFormat。
- Hadoop archive
Hive 优化
Spark 中尚未包含一些 Hive 优化。由于 Spark SQL 的内存计算模型,其中一些(例如索引)不太重要。其他一些已安排在 Spark SQL 的未来版本中。
- 块级位图索引和虚拟列(用于构建索引)
- 自动确定连接和 groupbys 的 reducer 数量:目前,在 Spark SQL 中,您需要使用“
SET spark.sql.shuffle.partitions=[num_tasks];
”来控制 post-shuffle 的并行度。 - 仅元数据查询:对于可以使用仅元数据回答的查询,Spark SQL 仍然启动任务来计算结果。
- Skew data flag:Spark SQL 不遵循 Hive 中的 skew data 标志。
- 连接中的
STREAMTABLE
提示:Spark SQL 不遵循STREAMTABLE
提示。 - 合并查询结果的多个小文件:如果结果输出包含多个小文件,Hive可以选择将这些小文件合并成较少的大文件,以避免HDFS元数据溢出。Spark SQL 不支持这一点。
Hive UDF/UDTF/UDAF
并非所有 Hive UDF/UDTF/UDAF 的 API 都受 Spark SQL 支持。以下是不支持的 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 视为秒。