生成唯一标识符

86

我是一名大学生,我们的任务是创建一个搜索引擎。但我在为每个URL生成唯一ID时遇到了困难。我已尝试使用SHA-256哈希算法和Guid。以下是我用于实现GUID的代码:

public string generateID(string url_add)
{
    long i = 1;

    foreach (byte b in Guid.NewGuid().ToByteArray())
    {
        i *= ((int)b + 1);
    }

    string number = String.Format("{0:d9}", (DateTime.Now.Ticks / 10) % 1000000000);

    return number;
}

2
GUID(全局唯一标识符)注定是全球唯一的(因此得名),所以我不明白问题在哪里。 - CodeCaster
我认为他的关注点是他希望基于URL的ID是唯一的,因此需要将URL进行单向哈希处理以生成唯一的ID。在这种情况下,SHA1是可行的。 - Richthofen
1
总是有 [object.GetHashCode()](http://msdn.microsoft.com/en-us/library/system.object.gethashcode.aspx) 的方法。虽然我不认为这个方法保证是唯一的。 - RichardTowers
@RichardTowers 这几乎可以保证是不唯一的 - CodesInChaos
32
简单的答案:return url_add; - CodesInChaos
如答案中所提到的,请查看Guid.NewGuid() - Samuel Parkinson
7个回答

137

为什么不直接使用 ToString 方法?

public string generateID()
{
    return Guid.NewGuid().ToString("N");
}

如果你想将其基于一个URL,你可以简单地执行以下操作:

public string generateID(string sourceUrl)
{
    return string.Format("{0}_{1:N}", sourceUrl, Guid.NewGuid());
}
如果你想要隐藏URL,你可以在sourceURL上使用SHA1的某种形式,但我不确定这样做能够达到什么效果。

这个可行... 我最初想让ID基于URL,但这似乎很好用。它能够生成大量的唯一键吗?因为搜索引擎将处理大量的URL。 - strange_developer
19
这将能够产生大约[5,316,911,983,139,663,491,615,228,241,121,400,000]个独特的值。 - Jaime Torres
谢谢!基于URL的方法也起作用了!我认为基于URL会使它更独特,减少冲突的机会!非常感谢!!! - strange_developer
我错误地将其写成了string.format而不是string.Format... 这是你遇到问题的原因吗? - Jaime Torres
为了更好的效果,请使用 String.Format("{0}_{1:N}", sourceUrl, Guid.NewGuid()) - abatishchev
显示剩余4条评论

40

为什么不使用GUID

Guid guid = Guid.NewGuid();
string str = guid.ToString();

34

这里是一个能生成'YouTube视频ID'(例如"UcBKmq2XE5a")的ID生成器。

StringBuilder builder = new StringBuilder();
Enumerable
   .Range(65, 26)
    .Select(e => ((char)e).ToString())
    .Concat(Enumerable.Range(97, 26).Select(e => ((char)e).ToString()))
    .Concat(Enumerable.Range(0, 10).Select(e => e.ToString()))
    .OrderBy(e => Guid.NewGuid())
    .Take(11)
    .ToList().ForEach(e => builder.Append(e));
string id = builder.ToString();

它创建11个字符大小的随机ID。您也可以增加/减少这个大小,只需更改Take方法的参数。

在1亿个ID中仅有0.001%的重复。


你认为在电子商务中使用这个作为订单号码可以吗?使用这种方法会有两个订单获得相同的ID的可能性吗?考虑到每天可能会有1K或10K个订单? - Mahamad Husen
我不建议在您的情况下使用上述方法。最好的选择是使用Guid。还可以查看此链接https://github.com/dotnet/aspnetcore/blob/master/src/Servers/Kestrel/shared/CorrelationIdGenerator.cs - Ashraf Ali
1
在我的情况下,如果我重新表述,我需要像你的解决方案一样的东西(一个大约8个字符的字母数字字符串),以便将其用作电子商务应用程序中的订单号,我刚刚将您的解决方案添加到我的项目中,并针对数据库检查重复项,如果有,则生成一个新的。 CorrelationIdGenerator类是否适合我的情况? - Mahamad Husen

9

为什么我们不能像下面这样创建唯一的id。

我们可以使用DateTime.Now.Ticks和Guid.NewGuid().ToString()结合在一起,生成唯一的id。

由于添加了DateTime.Now.Ticks,我们可以找到创建唯一id的日期和时间(以秒为单位)。

请参阅以下代码。

var ticks = DateTime.Now.Ticks;
var guid = Guid.NewGuid().ToString();
var uniqueSessionId = ticks.ToString() +'-'+ guid; //guid created by combining ticks and guid

var datetime = new DateTime(ticks);//for checking purpose
var datetimenow = DateTime.Now;    //both these date times are different.

我们甚至可以在唯一标识符中获取时间戳部分,并稍后检查日期和时间以供将来参考。

7

这个问题似乎已经有了答案,但为了完整起见,我会提供另一种方法。

您可以使用基于Twitter的Snowflake id生成器的唯一ID号码生成器。C#实现可以在这里找到。

var id64Generator = new Id64Generator();

// ...

public string generateID(string sourceUrl)
{
    return string.Format("{0}_{1}", sourceUrl, id64Generator.GenerateId());
}

请注意,该方法的一个非常好的特点是可以在独立节点上拥有多个生成器(对于搜索引擎可能非常有用),生成实时的全局唯一标识符。
// node 0
var id64Generator = new Id64Generator(0);

// node 1
var id64Generator = new Id64Generator(1);

// ... node 10
var id64Generator = new Id64Generator(10);

谢谢你的提示!正是我在寻找的。 - Sudhanshu Mishra
有一个NuGet代码位于https://github.com/RobThree/IdGen,它也使用类似的基于Snowflake的ID。FlakeId的Codeplex代码是否属于您?如果可以的话,我想将其转移到GitHub并进行NuGet处理。 - Sudhanshu Mishra
@dotnetguy,是的,我拥有那个项目。当然,你可以进行 GitHub 迁移和 Nuget 软件包的跟进。 - Tom

6
如果您想使用sha-256(GUID速度更快),那么您需要做类似于以下的操作。
SHA256 shaAlgorithm = new SHA256Managed();
byte[] shaDigest = shaAlgorithm.ComputeHash(ASCIIEncoding.ASCII.GetBytes(url));
return BitConverter.ToString(shaDigest);

当然,它不一定是 ASCII 编码,也可以是任何其他类型的哈希算法。


2
我会避免使用ASCII,而是选择一些Unicode编码。 通过你的代码很容易找到碰撞。 - CodesInChaos
我知道,这是因为我目前正在使用一个遗留系统,所以我对ASCII编码很熟悉 :) - daz-fuller
我希望根据URL使ID唯一。这是我考虑生成代码的方式。 - strange_developer

-4
我们可以像这样做:
string TransactionID = "BTRF"+DateTime.Now.Ticks.ToString().Substring(0, 10);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接