如何使用 spark.sql 将表列传递给 rand 函数?

Posted

技术标签:

【中文标题】如何使用 spark.sql 将表列传递给 rand 函数?【英文标题】:How to pass table column to rand function using spark.sql? 【发布时间】:2021-12-31 09:44:05 【问题描述】:

我有一张表,在 hive 元数据中有两列 AB。当AB 对的值与其他记录相同时,我必须生成相同的随机数。

示例:值对 2.0 & 3.01.0 & 5.0 在那些使用 HASH 函数的记录上我将得到 hash_code。这个hash_code 我将传递给随机函数以获取每个匹配记录的特定值。我可以简单地将 seed=123 传递给 rand 函数,但我无法将表列传递给 rand 函数。

编辑 1:

具有相同种子的函数rand(123)将产生identical results

将哈希传递给 rand:

spark.sql("select *,rand(hash(A,B)) from table1").show()

出现以下错误:

AnalysisException: Input argument to rand must be an integer, long, or null constant.

如何使用spark.sqlhash_code 传递给rand 函数?

【问题讨论】:

您使用的是哪个版本的 spark? @AlexandreJuma spark 3.0 即使可以将列传递给rand 函数,表达式rand(hash(A,B)) 也不会为相同的输入AB 给出相同的结果。这是一个非确定性函数。 rand 函数接受单个 Long 作为种子而不是列。 查看 Spark 代码,在 3.2.0 中 rand() 输入参数是严格的文字,因此没有来自列的可迭代输入。在您的版本中,您得到的错误似乎模棱两可,但它的行为似乎也相同。我不会使用rand(seed) 来生成确定性值,因为在没有一些低级功夫的情况下,实现(仍然)无法遵守种子随机数生成函数的通常确定性行为(即:将分区计数固定为 1 )。 【参考方案1】:

在我的 cmets 之后,使用 Spark 根本不可能(至少现在)您正在寻找的东西,主要有 2 个原因:

函数rand只能接受常量参数 此外,它是一个非确定性函数,因此在您的数据框中调用 rand(hash(A,B)) 不会对相同的输入 AB 给出相同的结果:
import pyspark.sql.functions as F

# the function rand is called with same value 123, still give different results
spark.range(3).withColumn("rand", F.rand(123)).show()

#+---+-------------------+
#| id|               rand|
#+---+-------------------+
#|  0|0.24244888714603952|
#|  1| 0.4745014193615499|
#|  2|0.03951602781768582|
#+---+-------------------+

也就是说,如果您的意图是从 AB 的哈希结果中得到一个介于 [0, 1] 之间的值,那么您可以通过将哈希除以 10...0length_of_hash 来使用此技巧:

spark.sql("""
SELECT  A, 
        B,  
        hash(A,B) / rpad('1', length(hash(A,B)) + 1, '0') AS Id  
FROM    table1
""").show()

#+---+---+------------+
#|  A|  B|          Id|
#+---+---+------------+
#|2.0|3.0|0.1475353518|
#|1.0|5.0| 0.649463331|
#|2.0|3.0|0.1475353518|
#|1.0|5.0| 0.649463331|
#+---+---+------------+

【讨论】:

【参考方案2】:

正如一些 cmets rand accepts only one parameter 所指出的,种子应该是一个常数,而不是一个列(这是您从 hash(A, B) 获得的)。

如果您的目的是从 AB 列中生成密钥,则不应调用任何随机函数。只需使用哈希值即可。

【讨论】:

我的目的是根据哈希码生成随机数。如果你仔细看 hash_code 是 long 或 big-int 数。我想要 [0,1) 之间的值

以上是关于如何使用 spark.sql 将表列传递给 rand 函数?的主要内容,如果未能解决你的问题,请参考以下文章

如何将多个数据框列传递给函数[重复]

如何将数据框列传递给scala函数

如何将两个数据框中的列传递给 Haversine 函数?

通过 URL 将几列传递给 orderBy 方法

将列传递给 UDF

python dataframe将两列传递给函数python