Однозначная хеш-функция для строки длиной 76 символов - PullRequest
3 голосов
/ 03 мая 2011

Вот моя проблема (я программирую на C):

У меня есть несколько огромных текстовых файлов, содержащих последовательности ДНК (каждый файл имеет что-то вроде 65 миллионов строк и размером около 4 ~ 5 ГБ).В этих файлах много дубликатов (пока не знаю, сколько их, но их должно быть много миллионов), и я хочу вернуть в выходной файл только отдельные значения.С каждой строкой связано значение качества, поэтому, если, например, у меня есть 5 одинаковых строк с разными значениями качества, я выберу наилучшую и откажусь от другой 4.

Сокращение требований к памяти и повышение эффективности по скорости, насколько яможет это жизненно важно.Моя идея состояла в том, чтобы создать массив JudyHS с использованием хеш-функции, чтобы преобразовать последовательность String DNA (длиной 76 букв и 7 возможных символов) в целое число, чтобы уменьшить использование памяти (4 или 8 байт вместо 76 байт во многих случаях).миллионы записей должны быть настоящим достижением).Таким образом, я мог бы использовать целое число в качестве индекса и хранить только лучшее значение качества для этого индекса.Проблема в том, что я не могу найти хеш-функцию, которая UNIVOCALLY определяет такую ​​длинную строку и выдает значение, которое может быть сохранено внутри целого числа или даже длинной длинной!

Моей первой идеей для хеш-функции былочто-то вроде строковой хеш-функции по умолчанию в Java: s [0] * 31 ^ (n-1) + s [1] * 31 ^ (n-2) + ... + s [n-1], но я могполучить максимальное значение 8,52 * 10 ^ 59 .. слишком большой.Как насчет того же и хранить его в двойном?Вычисления станут намного медленнее?Обратите внимание, что я бы хотел, чтобы способ UNIVOCALLY определял строку, избегая столкновений (или, по крайней мере, они должны быть крайне редкими, потому что мне пришлось бы обращаться к диску при каждом столкновении, довольно дорогая операция ...)

Ответы [ 2 ]

3 голосов
/ 03 мая 2011

У вас есть 7 ^ 76 возможных последовательностей ДНК и вы хотите сопоставить их с 2 ^ 32 хешами без коллизий?Невозможно.

Для этого требуется минимум log2 (7 ^ 76) = 214 бит, около 27 байт.

I Вы можете пережить некоторые коллизии, которые я бы рекомендовал придерживаться CRC32или md5 вместо того, чтобы изобретать новое колесо снова.

1 голос
/ 03 мая 2011

«Простой» способ получить хеш-функцию без столкновений для N элементов - это использовать хорошую функцию смешивания (скажем, криптографическую хеш-функцию) и урезать размер, чтобы хеш результаты живут в пространстве размером не менее N 2 . Здесь у вас есть 65 миллионов строк - это соответствует 26 битам ( 2 26 близко к 65 миллионам), поэтому 52 бита "должно быть достаточно".

Вы можете попробовать использовать быструю криптографическую хеш-функцию, даже «неработающую», поскольку это не связано с безопасностью. Затем MD4, MD5, SHA-1 ... обрезают результат до первых (или последних) 64 битов, сохраняя их в 64-битном целочисленном типе. Скорее всего, вы не получите никакого столкновения среди своих 65 миллионов строк; и если вы их получите, они будут очень редкими.

Для оптимизированных реализаций хеш-функций на языке C ищите sphlib . Используйте предоставленную функцию sph_dec64le() для «декодирования» последовательности из 8 битов в 64-разрядное целое число без знака.

...