Словарь с двумя хэш-функциями в С#?

У меня есть огромный (> 10 м) список записей. Каждая запись предлагает две хеш-функции:

  • Дешевый: быстро вычисляет хэш, но его распределение ужасно (может поместить 99% элементов в 1% хеш-пространства).
  • Дорогой: требует много времени для вычислений, но дистрибутив также намного лучше.

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

Кажется хорошей идеей использовать для этого словарь внутри словаря. В настоящее время я в основном использую это чудовище:

Dictionary<int, Dictionary<int, List<Foo>>>;

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

Он идеально подходит и безупречно справляется со своей задачей, но выглядит так, как будто он должен был умереть 65 миллионов лет назад.

Насколько мне известно, эта функциональность не включена в базовую структуру. Я собираюсь написать класс DoubleHashedDictionary, но сначала хотел узнать ваше мнение.

Что касается моего конкретного случая:
Первая хэш-функция = количество файлов в каталоге файловой системы (быстро) Вторая хеш-функция = сумма размеров файлов (медленно)

Правки:

  • Изменено название и добавлено больше информации.
  • Добавлена ​​довольно важная недостающая деталь

person mafu    schedule 23.11.2009    source источник
comment
Поправьте меня, если я ошибаюсь, но ваше описание двойного хэширования немного отличается от обычного использования этого термина (en.wikipedia.org/wiki/Double_hashing).   -  person Joey    schedule 23.11.2009
comment
Согласитесь с Йоханнесом, то, что здесь было описано, можно назвать отказоустойчивым хешированием.   -  person gn22    schedule 23.11.2009
comment
Да, в самом деле. Я думаю, что этот термин также используется для описания моей желаемой функциональности, но я могу ошибаться. Кто-нибудь знает правильный термин?   -  person mafu    schedule 23.11.2009
comment
На самом деле это называется Cuckoo Hashing: en.wikipedia.org/wiki/Cuckoo_hashing.   -  person Ben S    schedule 23.11.2009
comment
Бен: Хотя, вероятно, он ближе к хешированию с кукушкой, чем к двойному хэшированию, он все же не совсем подходит.   -  person Joey    schedule 23.11.2009


Ответы (4)


Во-первых, я думаю, что вы на правильном пути для реализации собственной хеш-таблицы, если то, что вы описываете, действительно желательно. Но как критик я хотел бы задать несколько вопросов:

Рассматривали ли вы использование чего-то более уникального для каждой записи?

Я предполагаю, что каждая запись представляет собой информацию о каталоге файловой системы. Рассматривали ли вы возможность использования ее полного пути в качестве ключа? префикс с именем компьютера / IP-адресом?

С другой стороны, если вы используете количество файлов в качестве хэш-ключа, эти каталоги никогда не изменятся? Потому что, если хеш-ключ/результат изменится, вы никогда не сможете найти его снова.

В этой теме, если содержимое/размер каталога никогда не изменится, можете ли вы сохранить это значение где-нибудь, чтобы сэкономить время, чтобы фактически вычислить это?

Просто мои несколько центов.

person Bill Yang    schedule 23.11.2009
comment
В моем случае использование пути или подобных дешевых частей DirectoryInfo, к сожалению, невозможно. --- Я более или менее позаботился об обработке изменений в файловой системе, это не большая проблема. --- Да я уже массово кеширую. Думаю, на другие расчеты потребуются годы. :) - person mafu; 23.11.2009
comment
принимая этот ответ, поскольку он наиболее близок к тому, что я сделал - реализация нового полнофункционального класса словаря с двумя хеш-функциями. - person mafu; 08.09.2010

В вашем случае вы технически используете модифицированную функцию (A | B), а не двойное хеширование. Однако, в зависимости от того, насколько огромен ваш «огромный» список записей и характеристик ваших данных, рассмотрите следующее:

  • Хеш-таблица, заполненная на 20%, с не очень хорошим распределением может иметь вероятность коллизии более 80%. Это означает, что ожидаемая стоимость функции может быть: (0,8 дорого + 0,2 дешево) + (стоимость поиска). Поэтому, если ваша таблица заполнена более чем на 20%, возможно, не стоит использовать схему (A|B).

  • Придумать идеальную хеш-функцию можно, но O(n^3), что делает ее непрактичной.

  • Если производительность чрезвычайно важна, вы можете создать специально настроенную хеш-таблицу для ваших конкретных данных, протестировав различные хеш-функции на ваших ключевых данных.
person MandoMando    schedule 23.11.2009
comment
Список может содержать около 100к-100м элементов. Случай 20/80, который вы описываете, вполне может произойти. Тем не менее, в моих тестах два хэша по-прежнему работали значительно лучше, чем всегда с использованием дорогого хэша. - person mafu; 23.11.2009
comment
Только что увидел ваши хеш-функции; Пробовали ли вы смешанную схему, такую ​​как #files in System + размер первых (n) файлов? Я полагаю, что будет небольшое n, которое даст вам лучшую отдачу от затраченных средств. Другие хорошо работающие функции — это умножение дешевого номера на размер первых (n) записей. По сути, добавляя немного соли к выводу функции. Вы будете удивлены, как быстро распространение пойдет по вашему пути. - person MandoMando; 23.11.2009
comment
Да, я думал об использовании только первых n размеров. Но, к сожалению, этот подход требует одинакового порядка файлов во всех каталогах, и я не могу этого гарантировать. Что-то вроде только n самых больших файлов также явно не работает. - person mafu; 23.11.2009
comment
Да, это было бы. Не могли бы вы использовать и смешивать другие атрибуты, такие как дата и время, имя, идентификатор и т. д.? Это позволит избежать выполнения дисковых операций (я предполагаю, что большие затраты на диск тратятся на вычисления оперативной памяти). - person MandoMando; 23.11.2009
comment
У @fyjham есть хорошая мысль. Вложенные словари не обязательно лучше одиночных словарей. - person MandoMando; 23.11.2009
comment
Нет, Datetime и т. д. в моем случае невозможны. Я сравниваю каталоги, сравнивая содержимое всех содержащихся в них файлов. - person mafu; 23.11.2009
comment
Ваше наблюдение 80-20 хорошее, но предполагает определенное распределение хеш-функций. Рассмотрим следующие два распределения: (1) 32-битный хеш будет отображать 99/6 553 600 элементов, которые будут отображаться в каждый из 65 536 слотов (и оставшаяся 1/100 элементов в равной степени с остальными); (2) 32-битная хэш-функция отображает 989/1000 элементов в одно хеш-значение, 1/1000 элементов в один из 4 000 000 слотов (равное расстояние) и 1/100 элементов в любой другой слот (равное расстояние). Оба дистрибутива будут иметь одно и то же свойство 99-1, но один может быть гораздо полезнее другого. - person supercat; 14.09.2011

Вы ознакомились с Power Collections или C5 Collections библиотеки? В библиотеке Power Collections в последнее время не было особых действий, но материал C5, похоже, довольно актуален.

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

person Brian Hasden    schedule 23.11.2009
comment
Я проверил оба из них, но не похоже, что они реализуют что-то, что я мог бы здесь использовать. - person mafu; 23.11.2009

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

Будет ли на самом деле значительное количество объектов, которые будут обнаружены с помощью механизма быстрого хеширования, без необходимости прибегать к более дорогим методам для дальнейшего сужения? Потому что, если вы не можете найти значительную сумму только при первом расчете, вы действительно ничего не сэкономите, сделав это в два этапа (не зная данных, трудно предсказать, так ли это).

Если это будет значительная сумма, расположенная за один шаг, вам, вероятно, придется немного настроить, чтобы определить, сколько записей хранить в каждом хэш-ячейке внешнего, прежде чем прибегать к внутренней «дорогой» хеш-таблице. поиск, а не дополнительная обработка хэшированных данных, но при определенных обстоятельствах я вижу, как вы получите прирост производительности от этого (обстоятельства будут немногочисленными, но не невероятными).

Редактировать

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

person fyjham    schedule 23.11.2009
comment
Второй хэш полностью переопределяет первый, поэтому я просто использовал словарь с одной дорогостоящей функцией (вместо XOR). Но оказалось медленнее. - person mafu; 23.11.2009