使用谷歌番石榴的Murmur3生成长而独特的id

时间:2017-01-12 12:42:30

标签: java guava uuid murmurhash

目前我正在尝试在客户端生成long类型的唯一标识符。 我有父/子关系,父母已经有一个UUID作为标识符。 我想考虑Parent-UUID来计算long类型的Child-Id。

我现在有这个实现:

public static void main(String[] args) {

    /** Funnel. */
    final Funnel<UUID> UUID_FUNNEL = new Funnel<UUID>() {
        @Override
        public void funnel(UUID parentUUID, PrimitiveSink into) {
            final UUID tmpId = UUID.randomUUID();
            into
             // consider parent uuid
            .putLong(parentUUID.getMostSignificantBits())
            .putLong(parentUUID.getLeastSignificantBits())
             // consider tmp uuid
            .putLong(tmpId.getMostSignificantBits())
            .putLong(tmpId.getLeastSignificantBits());
        }
    };

    final UUID parentUUID = UUID.randomUUID();
    System.out.println(parentUUID.toString());

    for (int i = 0; i < 1000; i++) {
        final long childId = Hashing.murmur3_128().newHasher()
                                .putObject(parentUUID, UUID_FUNNEL)
                                .hash().asLong();
        System.out.println(childId);
    }
}

您如何看待这个想法? 欢迎任何建议。

我已经读过这个问题: How to generate unique Long using UUID

1 个答案:

答案 0 :(得分:3)

这不会真的奏效。当然不比随机long好。

  • 没有tmpId:您只对parentUUID进行哈希处理,因此同一父级的所有子项都会获得相同的long
  • 使用tmpId:您可以使用UUID.randomUUID().getLeastSignificantBits()或仅使用random.nextLong()并自行保存所有工作(无论您添加什么,哈希随机值都会导致随机结果)。< / LI>
  

我有多个客户,而不仅仅是一个。

然后问一个独特的服务器。这包括一些开销,可以使用hi-lo algorithm轻松最小化。

  

在数据库级别,子ID必须是唯一的。

然后忘记它并让DB生成id。每个数据库都有一些AUTOINCREMENT或SEQUENCE意味着这一点。

如果您在访问数据库之前需要客户端中的id,请询问数据库(并使用hi-lo算法以最小化开销)。

离线工作

我刚刚看到你的评论:

  

客户端不应该去服务器获取下一个ID。必须可以脱机工作。

这是一个很大的痛苦。您可以做的任何哈希都不会比随机long好。

  • 一组一百万个随机long的碰撞几率约为1e-6,这可能是可以接受的。请注意,由于生日悖论,机会会随着设定的大小增加二次
  • 您可以尝试处理没有ID的离线创建实体(使用其他标识符),但这听起来很痛苦。
  • 您可以为每个客户端预分配一些ID。这听起来很浪费,但是为100万个客户端预先分配100个ID会占用所有可能ID的不到5%。
  • 您可以切换到随机UUID。由于它们长度为128位,即使数十亿个ID,碰撞几率也几乎为零。