在spark中有没有办法将md5散列转换成数字列?
尝试直接转换为十进制。也尝试过使用conv.but neigher work(请参见下文)。奇怪的是conv将不同的哈希值转换为相同的值。
(1 to 5).toDF("id")
.withColumn("md5_id", md5($"id".cast("string")))
.withColumn("conv_id", conv($"md5_id", 16, 10))
.withColumn("num_id", $"md5_id".cast(DecimalType(38,0)))
.show(false)
+---+--------------------------------+--------------------+-------+
|id |md5_id |conv_id |num_id|
+---+--------------------------------+--------------------+-------+
|1 |c4ca4238a0b923820dcc509a6f75849b|18446744073709551615|null |
|2 |c81e728d9d4c2f636f067f89cc14862c|18446744073709551615|null |
|3 |eccbc87e4b5ce2fe28308fd9f2a7baf3|18446744073709551615|null |
|4 |a87ff679a2f3e71d9181a67b7542122c|18446744073709551615|null |
|5 |e4da3b7fbbce2345d7772b0674a318d5|18446744073709551615|null |
+---+--------------------------------+--------------------+-------+
更新
如果其他人遇到同样的问题,这就满足了我的需要:
def toNum = udf((hex: String) =>
new java.math.BigInteger(hex.toUpperCase, 16)
)
(1 to 5).toDF("id")
.withColumn("hashed_id", toNum(substring(md5($"id".cast("string")), 0, 31)))
.show(false)
+---+--------------------------------------+
|id |hashed_id |
+---+--------------------------------------+
|1 |16348679641551244288068877217848318025|
|2 |16625230717330387431313232838613092450|
|3 |19672244359719724500030062827806555055|
|4 |13998420256418836516930895031794147618|
|5 |19012319408524223020738990858985681293|
+---+--------------------------------------+
root
|-- id: integer (nullable = false)
|-- hashed_id: decimal(38,0) (nullable = true)
1条答案
按热度按时间n9vozmp41#
嗯,这个案子很复杂,我会告诉你原因的。将md5转换为数字通常会创建一个
BigInteger
. 让我来演示一下如何在没有Spark的情况下完成:正如你所看到的,这个数字是巨大的,实际上大于你想要转换的38的十进制数,这个数字是39位。而spark不支持这种默认的数据类型转换。因此,解决这个问题的一种方法是使用带有自定义项的十进制库,但是会降低数据的精度。下面是如何做到这一点:
你可以看到结果是:
所以这就是为什么您要面对这个问题,md5数据的大小介于
1 and len(2^128-1)
大约是39位。因此,我建议或使用字符串,或转换成另一种类型。