Как быстро хэшировать URL-адрес

У меня есть уникальная ситуация, когда мне нужно производить хэши на лету. Вот мое положение. Этот вопрос связан с здесь. Мне нужно сохранить много URL-адресов в базе данных, которые необходимо индексировать. URL-адрес может содержать более 2000 символов. В базе жалуется, что строка более 900 байт не может быть проиндексирован. Мое решение-хэшировать URL-адрес с помощью MD5 или SHA256. Я не уверен, какой алгоритм хеширования использовать. Вот мои требования

  • короткий длина персонажа с минимальным столкновением
  • должен быть быстро. Я буду хэшировать referurl на каждом запросе страницы
  • конфликты необходимо свести к минимуму, так как у меня могут быть миллионы URL-адресов в базе данных

Я не беспокоюсь о безопасности. Я беспокоюсь о длине персонажа, скорости и столкновениях. Кто-нибудь знает хороший алгоритм для этого?

7 ответов


в вашем случае я бы не использовал ни одну из криптографических хэш-функций (т. е. MD5, SHA), так как они были разработаны с учетом безопасности: они в основном хотят, чтобы было как можно сложнее найти две разные строки с одним и тем же хэшем. Думаю, в твоем случае это не проблема. (возможность случайные столкновения присущи хешированию, конечно)

Я настоятельно не рекомендуем использовать String.GetHashCode(), Так как реализация не известна и MSDN говорит, что он может отличаться между различными версиями фреймворка. Даже результаты между версиями x86 и x64 могут отличаться. Таким образом, вы столкнетесь с проблемами при попытке получить доступ к той же базе данных, используя более новую (или другую) версию .NET framework.

Я нашел алгоритм для реализации Java hashCode в Википедии (здесь), кажется, довольно легко осуществить. Даже простая реализация будет быстрее, чем реализация MD5 или SHA imo. Вы также можете использовать long значения, которые уменьшают вероятность столкновений.

существует также краткий анализ .NET GetHashCode реализация здесь (не сам алгоритм, но некоторые детали реализации), вы также можете использовать этот один, я думаю. (или попробуйте реализовать версию Java аналогичным образом ...)


быстрый :

URLString.GetHashCode().ToString("x")

в то время как MD5 и SHA1 оказались неэффективными, когда предотвращение столкновений необходимо, я подозреваю, что для вашего приложения будет достаточно. Я не знаю точно, но я подозреваю, что MD5 будет проще и быстрее из двух алгоритмов.


использовать System.Security.Cryptography.SHA1Cng класс, я бы предложил. Это 160 бит или 20 байт длиной, так что это определенно должно быть достаточно маленьким. Если вам нужно, чтобы это была строка, она потребует только 40 символов, так что это должно соответствовать вашим потребностям. Он также должен быть достаточно быстрым, и, насколько мне известно, никаких столкновений пока не обнаружено.


Я бы лично использовал строку.GetHashCode (). Это основная хэш-функция. Я честно не знаю, как он работает по сравнению с другими реализациями, но это должно быть хорошо.

любая из двух функций хэширования, которые вы называете, должна быть достаточно быстрой, чтобы вы не заметили большой разницы между ними. Если этот сайт не требует сверхвысокой производительности, я бы не слишком беспокоился о них. Я бы лично, вероятно, пошел на MD5. Это может быть в виде строки, как hexdecimal в 64 символа или строки base-64 в 44 символов.

причина, по которой я бы пошел на MD5, заключается в том, что вы вряд ли столкнетесь с коллизиями, и даже если вы это сделаете, вы можете структурировать свои запросы с помощью "где urlhash = @hash и url = @url". Компонент database engine должен определить, что один индексируется, а другой нет, и использовать эту информацию для разумного поиска.

Если есть колизии, индексированное сканирование на urlhash вернет несколько результатов, которые будет легко сделать текстовые сравнения, чтобы получить правильный. Однако это вряд ли будет актуально очень часто. У вас довольно низкие шансы получить столкновения таким образом.


отраженный исходный код функции GetHashCode в .net 4.0

public override unsafe int GetHashCode()
{
    fixed (char* str = ((char*) this))
    {
        char* chPtr = str;
        int num = 0x15051505;
        int num2 = num;
        int* numPtr = (int*) chPtr;
        for (int i = this.Length; i > 0; i -= 4)
        {
            num = (((num << 5) + num) + (num >> 0x1b)) ^ numPtr[0];
            if (i <= 2)
            {
                break;
            }
            num2 = (((num2 << 5) + num2) + (num2 >> 0x1b)) ^ numPtr[1];
            numPtr += 2;
        }
        return (num + (num2 * 0x5d588b65));
    }
}

было O (n) простых операций (+,

я протестировал эту функцию на 3 млн ДБ, содержит строки длиной до 256 символов, и около 97% строк не имеют коллизии. (Максимум 5 строк имеют одинаковый хэш)


вы можете посмотреть на следующий проект:

CMPH-C минимальная идеальная библиотека хеширования

и ознакомьтесь со следующими горячими темами, перечисляющими идеальные хэши:

горячие ответы "perfect-hash" - переполнение стека

вы также можете рассмотреть возможность использования полнотекстового индекса в SQL, а не хэширования:

создать полнотекстовый индекс (Transact-SQL)