如果生成器(例如 UUID 的 Java 版本)未知,UUID 的哪些数字最不可能发生冲突?

Which digits of a UUID are least likely to collide if the generator (e.g. Java version of UUID) is unknown?

假设我们有一组现有的 UUID(例如,数百万,尽管这无关紧要)可能是由不同的客户端生成的,因此我们不知道生成任何 UUID 的算法。但我们可以假设它们是流行的实现。

是否有一组 8 个或更多数字(不一定连续,但理想情况下是)更不可能或更容易发生冲突?

例如,我在MySQL中看到uuid()函数,当在同一条语句中使用两次时,会生成2个完全相同的UUID,除了第5到第8位:

0dec7a69-ded8-11e8-813e-42010a80044f
0decc891-ded8-11e8-813e-42010a80044f
    ^^^^

一般的答案是什么?

该应用程序将公开一个更紧凑的 ID,供客户复制和粘贴或通过 phone 进行通信。不幸的是,我们必须在后端使用 UUID,并且可以理解地不愿意在 ID 的长版本和短版本之间创建映射,但是我们可以使用偶尔会发生冲突和 returns 超过 1 个结果的截断 UUID。

不管 UUID 规范的警告如何,只有一种方法可行。由于 UUID 本身旨在是全局唯一的,因此使用至少具有相同位大小的适当算法由它构成的安全哈希将具有相同的属性。 除了安全散列将通过散列值而不是特定位置具有熵。

例如,您可以这样做:

MessageDigest digest = MessageDigest.getInstance("SHA-256");
byte[] hash = digest.digest(uuid.toString().getBytes(StandardCharsets.UTF_8));

然后根据需要从散列中取出尽可能多的位,并将它们转换回字符串。

虽然这是一个单向函数;要以快速有效的方式将其映射回 UUID,您需要保留一个映射 table。 (您当然可以通过再次对 UUID 执行单向哈希来检查 UUID 是否与较短的代码匹配)

但是,如果您要从 UUID 中取出不连续的部分,则会遇到同样的问题。

建议:前 8 位数字

1c59f6a6-21e6-481d-80ee-af3c54ac400a
^^^^^^^^

给定版本的所有生成器实现都是 required to use the same algorithms,因此请担心后者而不是前者。

UUID version 1 & version 2 通常按照给定源的熵从大到小排列。因此,前 8 位数字可能最不可能发生冲突。

UUID version 4 and version 3 & 5 are designed to have uniform entropy, aside from the reserved digits for version and variant。所以前 8 位数字和其他数字一样好。