Spark SQL:array_contains和自动插入的强制转换

时间:2019-12-09 11:34:08

标签: apache-spark apache-spark-sql

在迁移到较新的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版本以外的其他内容,请随时发表评论,我将在问题中添加必要的数据。

1 个答案:

答案 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完成的。