在迁移到较新的Spark版本时,我们遇到了一个问题,完全不确定如何解决它。
我们有两个Spark实例,第一个是2.3.0版,第二个是2.4.0版。两个实例都收到相同的命令:
spark.sql("SELECT array_contains(array(1), '1')")
在旧版本中,我们得到以下信息:
[{"array_contains(array(1), CAST(1 AS INT))":true}]
即参数会自动广播以匹配另一个参数。 在较新的版本上,这是一个错误:
cannot resolve 'array_contains(array(1), '1')' due to data type mismatch: Input to function array_contains should have been array followed by a value with same element type, but it's [array<int>, string].; line 1 pos 7;
'Project [unresolvedalias(array_contains(array(1), 1), None)]
+- OneRowRelation
由于我们既没有明确控制传递给我们的实际数据类型也没有控制SQL代码(它们由客户管理),因此我们想了解他们是否必须更改数据,或者我们可以解决此问题发行自己。我们可以在Spark方面做些什么?
如果需要检查Spark版本以外的其他内容,请随时发表评论,我将在问题中添加必要的数据。
答案 0 :(得分:2)
这实际上在Spark Upgrading Guide中被引用:
在Spark 2.3及更早版本中,
array_contains
函数的第二个参数隐式提升为第一个数组类型参数的元素类型。此类型提升可能是有损的,并且可能导致array_contains
函数返回错误的结果。这个问题已在2.4中通过使用更安全的类型提升机制得到解决
因此,简而言之,在版本2.4中删除了要在数组中键入的第二个参数的隐式强制转换,您必须显式传递良好的类型:
spark.sql("SELECT array_contains(array(1), 1)")
Spark 2.4在内置的高阶函数中引入了另一个函数:exists
,它执行强制转换,但语法不同:
spark.sql("SELECT exists(array(1), x -> x=='1')").show()
它接受数组列和一个lambda函数,并转换为:
exists(array(1), lambdafunction((namedlambdavariable() = CAST(1 AS INT)), namedlambdavariable()))
如您所见,转换是由Spark完成的。