【问题标题】:How to generate a unique hash for a URL?如何为 URL 生成唯一哈希?
【发布时间】:2009-10-27 08:22:02
【问题描述】:

鉴于这两张来自 twitter 的图片。

http://a3.twimg.com/profile_images/130500759/lowres_profilepic.jpg
http://a1.twimg.com/profile_images/58079916/lowres_profilepic.jpg

我想将它们下载到本地文件系统并将它们存储在一个目录中。 我该如何克服名称冲突?

在上面的示例中,我无法将它们存储为 lowres_profilepic.jpg。 我的设计理念是将 URL 视为不透明的字符串,除了最后一段。 我可以使用哪些算法(实现为 f)将前缀散列成唯一的字符串。

f( "http://a3.twimg.com/profile_images/130500759/" ) = 6tgjsdjfjdhgf
f( "http://a1.twimg.com/profile_images/58079916/" )  = iuhd87ysdfhdk

这样,我可以将文件保存为:-

6tgjsdjfjdhgf_lowres_profilepic.jpg
iuhd87ysdfhdk_lowres_profilepic.jpg

我不想要加密算法,因为它需要是一个高性能操作。

【问题讨论】:

  • 您是否真的在您的平台上对加密哈希进行了基准测试?除非您使用的是 20 年前的硬件,否则散列短字符串不太可能与首先获取图像一样。

标签: algorithm


【解决方案1】:

无论您如何操作(散列、编码、数据库查找),我都建议您不要尝试将大量 URL 映射到大型平面目录中的文件。 p>

原因是大多数文件系统的文件查找涉及对目录中文件名的线性扫描。因此,如果您的所有 N 个文件都在一个目录中,则查找将平均涉及 1/2 N 次比较;即O(N)(请注意,ReiserFS 将目录中的名称组织为 BTree。但是,ReiserFS 似乎是例外而不是规则。)

最好将 URI 映射到目录树,而不是一个大的平面目录。根据树的形状,查找可以与O(logN) 一样好。例如,如果您将树组织为具有 3 级目录,每个目录中最多 100 个条目,则可以容纳 100 万个 URL。如果您将映射设计为使用 2 个字符的文件名,则每个目录应该可以轻松放入单个磁盘块中,并且路径名查找(假设所需的目录已经缓存)应该需要几微秒。

【讨论】:

  • 现在的文件系统通常使用树作为文件结构。
  • 大型扁平目录可能导致性能问题还有其他原因;例如读取和排序目录条目的程序。
  • 即使在今天,如果您在一个文件夹中有大量文件,Windows 仍然会自行崩溃。另外,如果您有多个文件夹,则可以一次删除一个文件夹,以防止整个缓存立即过期。
【解决方案2】:

看来您真正想要的是拥有一个不会与其他人冲突的合法文件名。

  • URL 的任何编码都可以使用,即使是 base64:例如filename = base64(url)
  • 加密哈希可以满足您的需求 - 尽管您声称这将成为性能瓶颈,但在您进行基准测试之前不要确定

【讨论】:

    【解决方案3】:

    哈希的本质是它可能导致冲突。这些替代方案之一怎么样:

    1. 使用目录树。从字面上为 URL 的每个组件创建子目录。
    2. 生成唯一标识。这里的问题是如何保持真实姓名和保存的id之间的映射。您可以使用在 URL 和生成的唯一 ID 之间进行映射的数据库。您可以简单地将一条记录插入到生成唯一 ID 的数据库中,然后使用该 ID 作为文件名。

    【讨论】:

    • 我确实考虑过为此使用数据库。
    • 所有性能都是相对的 - 将一个额外的记录滑入本地数据库可能与下载图像相比相当不错。当然,这不是可以完成的最快的事情,但我更喜欢可以工作的最简单的事情,直到它被证明太慢。
    【解决方案4】:

    URL 的关键概念之一是它是唯一的。为什么不使用它?

    每个缩短信息的算法都可能产生冲突。也许不太可能,但还是有可能

    【讨论】:

    • 看起来他正在使用与推特相关的东西
    • 这是最简单的方法,但他需要注意某些操作系统(即 XP)上 255 个字符的路径限制。请注意,实际 URL 可能小于 255,但与父文件夹结合起来可能会更长,这很痛苦。有些网址可能长得离谱!
    • XP 上的 path 限制为 32767。并非所有文件系统都支持它(例如 CD-ROM 通常不支持),单独的 names 在路径限制为 255 个字符,您可能需要在某些 API 中使用带有 `\\?` 前缀的完整内部路径名。
    【解决方案5】:

    一个非常简单的方法:

    f( "http://a3.twimg.com/profile_images/130500759/" ) = a3_130500759.jpg
    f( "http://a1.twimg.com/profile_images/58079916/" )  = a1_58079916.jpg
    

    由于此 URL 的其他部分是不变的,您可以使用子域,即查询路径的最后一部分作为唯一文件名。

    不知道这个解决方案有什么问题

    【讨论】:

    • 如果 Twitter 改变他们的图片托管服务器怎么办?就在一年前,个人资料图片还存储在 s3 上。
    • 嗯,这确实是个问题。
    【解决方案6】:

    虽然 CRC32 无论您的输入如何都会产生最大 2^32 的值,因此不会避免冲突,但对于这种情况,它仍然是一个可行的选择。

    它很快,所以如果您生成的文件名有冲突,只需在您的 URL 中添加/更改一个字符,然后重新计算 CRC。

    43 亿个可能的校验和意味着文件名冲突的可能性与原始文件名相结合,将非常低,以至于在正常情况下并不重要。

    我自己也将这种方法用于类似的事情,并且对性能感到满意。 见Fast CRC32 in Software.

    【讨论】:

      【解决方案7】:

      您可以使用 Java 中的 UUID 类从唯一的字节生成 UUID 中的任何内容,并且您不会遇到文件查找问题

      String url = http://www.google.com;
      String shortUrl = UUID.nameUUIDFromBytes("http://www.google.com".getBytes()).toString();
      

      【讨论】:

        【解决方案8】:

        我知道你的问题是什么是最好的哈希算法。你可能想检查这个Best hashing algorithm in terms of hash collisions and performance for strings

        【讨论】:

          【解决方案9】:

          git 内容管理系统基于 SHA1,因为它发生冲突的机会非常小。

          如果它对 git 有好处,那么它对你也有好处。

          【讨论】:

          • 没有加密算法,请参阅问题。
          • 这是 2009 年,我无法想象短 url-s 会很慢。
          • 我知道,但如果问题开启者不想拥有加密算法,那么您的回答将无济于事。
          • 此应用可在手机上运行。
          • 我同意你的观点,在问题描述中不要使用它。现在我看到它将在手机上,所以我猜你不需要解析数千个 url/秒。手机可以播放需要更多计算的视频。我只是说值得用现有库而不是困难的方法来衡量 sha1 的性能。
          【解决方案10】:

          我正在使用 thumbalizr 使用他们缓存脚本的修改版本,我认为它有一些很好的解决方案。代码在 github.com/mptre/thumbalizr 但简短版本是使用 md5 构建文件名,它从文件名中获取前两个字符并使用它来创建一个文件夹,该文件夹的名称完全相同.这意味着很容易分解文件夹,并且无需数据库即可快速找到相应的文件夹。它的简单让我大吃一惊。

          它会生成这样的文件名 http://pappmaskin.no/opensource/delicious_snapcasa/mptre-thumbalizr/cache/fc/fcc3a328e0f4c1b51bf5e13747614e7a_1280_1024_8_90_250.png

          最后一部分 _1280_1024_8_90_250 与脚本在与 thumbalizr api 对话时使用的不同设置相匹配,但我猜 fcc3a328e0f4c1b51bf5e13747614e7a 是 URL 的直接 md5,在​​本例中为 thumbalizr.com

          我尝试更改配置以生成 200px 宽的图像,并且图像位于同一个文件夹中,但它不是 _250.png,而是称为 _200.png

          我还没有时间深入研究代码,但我确信它可以从 thumbalizr 逻辑中分离出来并变得更通用。

          【讨论】:

            【解决方案11】:

            你说:

            我不想要加密算法,因为它需要是一个高性能操作。

            嗯,我理解您对速度的需求,但我认为您需要考虑您的方法的缺点。如果您只需要为 url 创建哈希,则应该坚持使用它,不要编写新算法,例如,您需要处理冲突。

            因此,您可以使用Dictionary<string, string> 来缓存您的网址。因此,当您获得一个新地址时,您首先在该列表中进行查找,如果未找到匹配项,则对其进行哈希处理并存储以备将来使用。

            按照这一行,你可以试试 MD5:

            public static void Main(string[] args)
            {
                foreach (string url in new string[]{ 
                    "http://a3.twimg.com/profile_images/130500759/lowres_profilepic.jpg", 
                    "http://a1.twimg.com/profile_images/58079916/lowres_profilepic.jpg" })
                {
                    Console.WriteLine(HashIt(url));
                }
            }
            
            private static string HashIt(string url)
            {
                Uri path = new Uri(new Uri(url), ".");
                MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
                byte[] data = md5.ComputeHash(
                    Encoding.ASCII.GetBytes(path.OriginalString));
                return Convert.ToBase64String(data);
            }
            

            你会得到:

            rEoztCAXVyy0AP/6H7w3TQ==
            0idVyXLs6sCP/XLBXwtCXA==
            

            【讨论】:

              【解决方案12】:

              twimg.com URL 的数字部分似乎已经是每个图像的唯一值。我的研究表明这个数字是连续的(即下面的示例 url 是用于上传的第 433,484,366 个个人资料图片 - 这恰好是我的)。因此,这个数字是唯一的。我的解决方案是简单地将文件名的数字部分用作“哈希值”,而不必担心会找到非唯一值。

              • 网址:http://a2.twimg.com/profile_images/433484366/terrorbite-industries-256.png
              • 文件名:433484366.terrorbite-industries-256.png
              • 唯一 ID:433484366

              我已经将此系统用于显示新推文通知的 Python 脚本,作为其操作的一部分,它会缓存个人资料图像缩略图以减少不必要的下载。

              附:从哪个子域下载图像没有区别,所有图像都可以从所有子域获得。

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2014-12-31
                • 2013-07-29
                • 2017-04-09
                • 1970-01-01
                • 1970-01-01
                • 2019-11-30
                相关资源
                最近更新 更多