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

Posted

技术标签:

【中文标题】Spark SQL:array_contains 和自动插入的强制转换【英文标题】:Spark SQL: array_contains and auto-inserted casts 【发布时间】:2019-12-09 11:34:08 【问题描述】:

我们在迁移到较新的 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】:

这个其实是在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 完成。

【讨论】:

这意味着如果它真的像array_contains(array(item1, item2, ... itemn), item),所有变量都由用户提供,他们将不得不使用显式转换? 是的,很遗憾!除非您想检测用户引入的 SQL 并通过转换为正确的类型(我不推荐)来更改为查询,否则他们将不得不进行显式转换。也可以在答案中查看我的编辑。

以上是关于Spark SQL:array_contains 和自动插入的强制转换的主要内容,如果未能解决你的问题,请参考以下文章

大数据之Hive:array_contains

array_contains 等效于 HiveQL 中的 JSON

配置单元中的 ARRAY_CONTAINS 多个值

Angular firestore array_contains 对象

我想知道 BigQuery 中 Array_contains 的类似功能。我正在尝试获取 Array of Struct 字段中存在的多个值的结果

spark-sql 与 spark-shell REPL 中的 Spark SQL 性能差异