Обычный подход (по крайней мере, для меня) состоит в том, чтобы разделить вашу битовую строку на несколько кусков и запросить у этих кусков точное соответствие в качестве шага предварительной фильтрации. Если вы работаете с файлами, вы создаете столько файлов, сколько у вас есть блоков (например, 4 здесь) с каждым блоком, переставленным впереди, а затем сортируете файлы. Вы можете использовать бинарный поиск и даже расширить свой поиск выше и ниже соответствующего блока для бонуса.
Затем вы можете выполнить побитовое вычисление расстояния Хэмминга для возвращенных результатов, которое должно быть только меньшим подмножеством вашего общего набора данных. Это можно сделать с помощью файлов данных или таблиц SQL.
Итак, резюмируем: скажем, у вас есть набор 32-битных строк в БД или файлах, и вы хотите найти каждый хеш, который находится на расстоянии 3-х битного расстояния Хемминга или меньше от вашей битовой строки запроса:
создайте таблицу с четырьмя столбцами: каждый из них будет содержать 8-битный (в виде строки или целого) срез из 32-битных хэшей, с 1 по 4. Или, если вы используете файлы, создайте четыре файла, каждый из которых перестановка срезов, имеющих по одному «островку» в начале каждой «строки»
разделить битовую строку запроса таким же образом в qslice 1 до 4.
запросить эту таблицу так, чтобы любой из qslice1=islice1 or qslice2=islice2 or qslice3=islice3 or qslice4=islice4
. Это дает вам каждую строку, которая находится в пределах 7 бит (8 - 1
) от строки запроса. При использовании файла выполните бинарный поиск в каждом из четырех переставленных файлов для получения одинаковых результатов.
для каждой возвращенной строки битов, вычисляйте точное расстояние Хемминга попарно с битовой строкой вашего запроса (реконструируя битовые строки индекса на основе четырех секций либо из БД, либо из переставленного файла)
Количество операций на шаге 4 должно быть намного меньше, чем полное парное вычисление Хэмминга всей вашей таблицы, и очень эффективно на практике.
Кроме того, можно легко разделить файлы на файлы меньшего размера, поскольку для повышения скорости требуется параллелизм.
Теперь, конечно, в вашем случае вы ищете своего рода самообъединение, то есть все значения, которые находятся на некотором расстоянии друг от друга. Тот же подход по-прежнему работает IMHO, хотя вам придется расширяться вверх и вниз от начальной точки для перестановок (с использованием файлов или списков), которые разделяют начальный блок и вычисляют расстояние Хемминга для результирующего кластера.
При работе в памяти вместо файлов ваш 100-битный 32-битный набор данных будет в диапазоне 4 ГБ. Следовательно, для четырех перестановочных списков может потребоваться около 16 ГБ ОЗУ. Хотя вместо этого я получаю отличные результаты с файлами, отображенными в память, и требует меньше оперативной памяти для наборов данных аналогичного размера.
Доступны реализации с открытым исходным кодом. ИМХО лучшим в этой области является тот, который сделан для Simhash от Moz , C ++, но предназначен для 64-битных строк, а не 32-битных.
Этот подход с ограниченным расстоянием хаппинга был впервые описан AFAIK Моисеем Чарикаром в его "simhash" семенной бумаге и соответствующем патенте Google :
- ПРИБЛИЖЕННЫЙ ПОСЛЕДНИЙ ПОИСК СОСЕДЕЙ В ПРОСТРАНСТВЕ ХАММИНГА
[...]
Учитывая битовые векторы, состоящие из d битов каждый, мы выбираем
N = O (n 1 / (1+)) случайных перестановок битов. Для каждого
случайная перестановка σ, мы поддерживаем отсортированный порядок O σ
битовые векторы в лексикографическом порядке переставленных битов
по σ. Учитывая битовый вектор запроса q, мы находим приблизительный
ближайший сосед, выполнив следующие действия:
Для каждой перестановки σ мы выполняем двоичный поиск по O σ, чтобы найти
два битовых вектора, ближайших к q (в лексикографическом порядке, полученном битами, переставленными σ). Теперь мы ищем в каждом из
отсортированные заказы O σ проверяют элементы сверху и снизу
позиция, возвращаемая двоичным поиском в порядке
длина самого длинного префикса, соответствующего q.
Моника Хензигер подробно остановилась на этом в своей статье "Поиск почти дублированных веб-страниц: масштабная оценка алгоритмов" :
3.3 Результаты для алгоритма C
Мы разбили битовую строку каждой страницы на 12
перекрытие 4-байтовых фрагментов, создание 20-битных фрагментов и вычисление C-подобия всех страниц, на которых был хотя бы один
штука общая. Такой подход гарантированно найдет все
пары страниц с разницей до 11, т.е. С-сходство 373,
но может пропустить некоторые из них для больших различий.
Это также объясняется в статье Обнаружение почти дубликатов для веб-сканирования Гурмит Сингх Манку, Арвинд Джайн и Аниш Дас Сарма:
- ПРОБЛЕМА ХАММИНГА РАССТОЯНИЯ
Определение: дано собрание f-битных отпечатков пальцев и
запрос отпечатка пальца F, определить, есть ли существующий отпечаток пальца
отличается от F не более чем на k бит. (В пакетном режиме
из вышеупомянутой проблемы, у нас есть набор отпечатков запросов
вместо одного отпечатка запроса)
[...]
Интуиция: рассмотрим отсортированную таблицу из 2 d f -битных действительно случайных отпечатков пальцев. Сосредоточьтесь на самых значимых битах
в таблице. Список этих d-битных чисел составляет
«Почти счетчик» в том смысле, что (а) довольно много
комбинации существуют, и (б) очень мало комбинаций d-битов
дублируется. С другой стороны, наименее значимый f - d
биты «почти случайны».
Теперь выберите d такой, что | d - d | это небольшое целое число. поскольку
таблица отсортирована, достаточно одного зонда для идентификации всех отпечатков пальцев, которые соответствуют F в d наиболее значимых битовых позициях.
Так как | d - d | мал, количество таких совпадений также
ожидается быть маленьким. Для каждого соответствующего отпечатка пальца мы можем
легко определить, отличается ли он от F не более чем на k битовых позиций
или нет (эти различия, естественно, будут ограничены
f - d младших значащих битовых позиций).
Процедура, описанная выше, помогает нам найти существующий
отпечаток пальца, который отличается от F в k битовых позициях, все из которых
ограничены, чтобы быть среди наименее значимых битов f - d
F. Это заботится о значительном числе случаев. Чтобы покрыть все
случаях достаточно построить небольшое количество дополнительных
отсортированные таблицы, как это официально описано в следующем разделе.
Примечание. Я отправил аналогичный ответ на связанный только с БД вопрос