Pyspark HASH() 能否安全地将 UUID/GUID 转换为 BIGINT 并保持 Databricks 中的唯一性?

问题描述 投票:0回答:1

背景

我正在开发 Databricks Lakehouse 实现,我们正在为多个表创建一些代理键,以促进标准化下游连接。我们的数据来自许多不同的系统,这些系统使用不同类型的标识符键,我们正在将它们标准化为使用一个代理键。

我们首先使用

expr("uuid()")
生成 UUID 作为我们的密钥。然而,在进一步的研究中,如果我们可以使用
BIGINT
(
LongType()
) 代理键来代替,我们似乎可以实现更好的存储效率和查询性能。

表的大小:在生成键的参考主表中,我们正在查看 200-300k 行。在具有外键引用的下游引用表中,我们有数十亿和数万亿行范围的表。

我们尝试过的替代方案

花了一些时间调查 Delta Lake 的新IDENTITY 列是否可以满足此要求。它确实提供了 BIGINT 键生成,但它有一个主要限制,即如果使用

IDENTITY
列定义表,则它无法接收来自多个传入源的并发写入。这是此视频中对此功能的讨论中提到的主要限制。

潜在的解决方案?

查看将

uuid()
调用包装在
xxHash64()
函数中,以将 UUID 哈希为 BIGINT。查看 标准 pyspark.sql 哈希函数列表 这个函数似乎可以确保我们有一个 BIGINT (尽管考虑到我们的行大小,也许只有 32 位
hash()
也可以工作?)

问题

  1. 这样做
    withColumn('id', F.xxHash64(F.expr("uuid()")))
    是个好主意吗?似乎会满足要求,但不确定这种方法在性能或潜在重复方面是否存在任何隐藏的问题。
  2. 如果
    uuid()
    函数保证唯一性,那么对其进行哈希处理也会产生唯一值,这样的假设是否有效?
  3. 我们需要使用 64 位哈希还是 32 位哈希就足够了(行数少于 1M)?
python database apache-spark pyspark databricks
1个回答
0
投票

UUID 的长度为 128 位(存储为 36 个字符的字符串),Long 的长度(无论是否哈希)仅为 64 位。 你会遇到碰撞。 您可以将 uuid 字符串转换为两个 long 来存储它们,尽管在本机 Spark 中并不容易/高效(long_pair_from_uuid 提供了该功能,但在撰写本文时没有 python 包装器)。

Quality 的 unique_id 允许通过将雪花 id 方法与 Spark 分区相结合来进行并发写入,而无需 rng 的开销。 (驱动程序节点的网卡上的 MAC 地址在网络上必须是唯一的,以获得“全局”ID)。 在撰写本文时,还没有受支持的 python 包装器。

这种方法还有其他好处,例如查找,搜索两个长整型(以及具有 Quality id 的 Int)比字符串和存储要快得多。 主要缺点是集成诸如 power bi 查找之类的东西可能会变得低效,因为链接 64 位长整型不起作用,因此您必须回退到字符串(这导致 Quality 添加

optimizers 将字符串转换为底层 id 进行查找)。

使用 uuid(spark 或 Quality)时有一个更大的问题,您需要注意它们是不确定的,如果您只是在写出之前使用它们,那没问题,但如果您使用它们进行连接(不使用写入磁盘的结果)那么你会得到非常

令人惊讶的行为

© www.soinside.com 2019 - 2024. All rights reserved.