Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
РГР №1.docx
Скачиваний:
8
Добавлен:
07.12.2018
Размер:
243.68 Кб
Скачать

Виртуальное хэширования

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

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

1) каждая запись идентифицируется каким-то значением c (ключом r),

2) множество C из всех возможных ключей очень велико, если его сравнивать с количеством x одновременно хранимых записей.

Идея хеширования состоит в том, чтобы «обрубать» некоторые аспекты ключа и использовать эту частичную информацию как основание для поиска. Конкретнее это можно представить следующим образом:

  1. Выделяется N > 1 ячеек памяти (так называемых блоков). Блоки идентифицируются по их адресам m, m = {0, 1 … , N – 1} и могут содержать до b >= 1 записей. Для того, чтобы посмотреть содержимое блока, нужно обратиться к диску один раз.

  2. Для хранения и поиска записи r используется хеш-функция h : C> {0, 1, … , N – 1}. h(c) псевдослучайная функция; говорится что хеширование случайно, если любой адрес может быть выбран с той же самой вероятностью. h(c) – это прямой (начальный) адрес для записи r ; блок h(c) называется прямым (начальным) блоком. Когда требуется найти запись r, поиск начинается с обращения к блоку h(c). Когда требуется записать r, мы записываем ее в блок h(c), если этот блок еще не заполнен. Если же он заполнен, то возникает так называемая коллизия.

  3. Когда решено, что создается множество записей F, выбрав h, скажем h`. Затем, если встречается коллизия, чтобы ее разрешить, мы вычисляем адрес m1 h`(c). Затем запись r (или иногда другая запись r блока h`(c)) записывается в блок m1, если он не заполнен. Если же заполнен, то мы продолжаем вычислять адрес m2, m2 m1, m2 h`(c), и т.д. Когда ведется поиск r, мы обращаемся к блоку h`(c), а затем уже можем обратиться ко всем mi для этого блока.

Избыточной записью (коротко – переполнение) запись r, если r записана по адресу m ≠ h(c). Метод разрешения коллизий (CRM) – это алгоритм, который разрешает коллизии. Каждая хеш-функция и CRM широко изучались с середины 50-х годов ХХ века. Обычно, для небольших объемов данных и простых алгоритмов определяют хеш-функцию как h : c–>c mod N (хеширование методом деления).

Это значит, в особенности, что если F – файл, т.е. записан на диске или другом носителе, и мы используем хеширование как метод доступа, то обращение к диску нужно только тогда, когда мы обращаемся к блоку. Хеширование лучше относительно этой особенности, чем другие обычные методы доступа (ISAM, VSAM, B-tress, …), так как они используют функции, обычно описываемые большими таблицами. Задав x (общее количество записей), обычно просто найти h, у которой коэффициент загрузки α = x/bN высокий, скажем 0.7 ≤ α ≤ 0.9, что приведет к минимальному количеству переполнений так, чтобы почти каждая запись находилась за один доступ. Это особенно актуально для хеширования методом деления.

Однако, если окажется, что x << Nb, то блоки будут загружены мало. С другой стороны, если x ≈ Nb или x >> Nb, то появится больше переполнений, и их количество будет быстро расти вместе с α. Нам сразу потребуется делать уже несколько запросов посредством поиска, что серьезно ухудшает доступ. Хеширование, таким образом, эффективно, если x остается близким к для которого мы уже выбрали Nb так, чтобы был высокий коэффициент α и, соответственно, быстрый доступ.

Это проблема часто раздражает, когда сложно угадать или x часто меняется, например, xmax / xmin ≥ 5. В случае, когда растет x, замедление доступа более актуально, чем недогруженные блоки. Поэтому ниже мы решаем, по существу, проблему вставок.

Вставки должны создавать коллизии. Правило (3) предполагает, что коллизия должна создать переполнение, и, таким образом, доступ должен замедляться. Если мы хотим избежать этого, мы должны допускать как можно меньше переполнений. Это значит, что CRM должен изменять h.

Это рассуждение показывает, что принципы, изложенные в начале второго предложения правила (3), являются ограничением идеи хеширования. Они также влекут за собой дополнительное предположение, что поиск, удаление или вставка не могут модифицировать h’. Мы назовем классическим хешированием хеширование, отвечающее данному предположению, против виртуального хеширования (VH), которое может изменять h в течение одной из этих операций. Несмотря на множество работ, посвященных хешированию, нет ни одной работы по виртуальному хешированию, и очень мало работ по проблеме изменения h; вероятно, из-за кажущейся неэффективности виртуального хеширования.

Действительно, пусть h’ будет функция до коллизии для адреса m, а h’’ – новая. Записи, которые поменяли адрес, должны быть повторно вставлены. Однако, если h’’ – простая функция, то, обычно, не только записи блока m, но также несколько других записей меняют свои адреса. В этом случае, вероятно, лучше перехешировать F, т.е. переставить каждую запись на новое место. Можно предлагать «благоразумный путь» борьбы со вставками; он состоит из последовательности перехеширований функциями h’,h’’,h’’’,… так, что h’’ адресует вдвое больше блоков, чем h’ и т.д. Конечно, VH, используя перехеширование, не имел бы смысла.

С другой стороны, если мы также внимательно выбираем записи, которые будут перемещены, как и их адреса, то алгоритм h’’, обычно, далек от своего простого первого. Главным образом, могут потребоваться большие и безмерные основные таблицы. Это значит, что теряются основные преимущества хеширования.

В сложившейся ситуации единственно возможный путь – компромисс между двумя неэффективностями. Такой компромисс может базироваться на следующих предположениях:

  • перевставки должны использовать незначительное число обращений к диску. Изменение адресов должно касаться только записей, которые уже в ядре. Как правило, только записи блока m и его переполнений находятся в ядре, когда обнаруживается коллизия. Логично предположить, что только c Cm = h­­­­­’–1(m) может поменять адрес.

  • новые адреса и переносимые записи должны быть выбраны простым алгоритмом. Адреса должны поменяться для некоторых ключей c Cm , но не для всех. Обычно h с областью определения (с набором ключей) Cm и такая, что h–1(m) ≠ 0 , кажется идеальным вариантом.

Такие h разбивают (расщепляют) Cm . Мы покажем, что виртуальное хеширование, использующее разделение, может быть удивительно эффективным и преодолеть главные дефекты классического хеширования, по крайней мере, когда обращается к файлу.