Структура данных для поиска близлежащих ключей со схожими значениями бит

У меня есть данные, содержащие от миллиона до миллиарда записей, каждая из которых представлена ​​битовым полем, около 64 бит на ключ. Биты независимы, вы можете представить их в основном как случайные биты.

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

Какой алгоритм/структура данных будет эффективно искать все записи, наиболее похожие на похожие в ключ запроса? Здесь аналогичное означает, что большинство бит идентичны, но минимальное число допускается неправильно. Это традиционно измеряется расстояние Хэмминга., которое просто подсчитывает количество несогласованных бит.

Можно сделать два способа, чтобы этот запрос мог быть задан, указав скорость несоответствия, например "дайте мне список всех существующих ключей, которые имеют менее 6 бит, которые отличаются от моего запроса", или просто лучшими совпадениями, такими как "дайте мне список из 10 000 ключей, которые имеют самое низкое количество разных бит из моего запроса."

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

Проблема может быть решена с помощью простого грубого силового тестирования хеш-таблицы для низкого количества бит. Если мы хотим найти все ключи, которые отличаются от одного запроса от нашего запроса, например, мы можем перечислить все 64 возможных ключа и проверить их все. Но это быстро взрывается, если мы хотим разрешить две биты разницы, тогда нам придется прощупывать 64 * 63 = 4032 раза. Он становится экспоненциально хуже для большего количества бит.

Итак, есть ли другая структура данных или стратегия, которая делает этот тип запросов более эффективным? База данных/структура может быть предварительно обработана столько, сколько вам нравится, это скорость запроса, которую следует оптимизировать.

Ответ 1

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

BK-деревья, как правило, описываются со ссылкой на текст и используют расстояние levenshtein для построения дерева, но просто написать его в терминах двоичных строк и расстояния hamming.

Ответ 2

Это звучит как хорошая подгонка для S-Tree, которая похожа на иерархический инвертированный файл. Хорошие ресурсы по этой теме включают следующие документы:

Иерархический индекс битовой карты: эффективная и масштабируемая технология индексирования для атрибутов с установленными знаками.

Улучшенные методы для построения дерева подписи (2000)

Цитата из первого:

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

Эти документы включают ссылки на другие исследования, которые могут вам пригодиться, например M-Trees.

Ответ 3

Создайте двоичное дерево (в частности, trie), представляющий каждый ключ в вашем старте следующим образом: Корневой node это пустое слово, перемещение вниз по дереву слева добавляет 0 и движение вниз справа добавляет 1. Дерево будет иметь только столько листьев, что и ваш начальный набор имеет элементы, поэтому размер должен оставаться управляемым.

Теперь вы можете сделать рекурсивный обход этого дерева, позволяя не более n "отклонений" от ключа запроса в каждой рекурсивной строке выполнения, пока не найдете все узлы в стартовом наборе, которые находятся в пределах этого числа отклонения.

Ответ 4

Я бы пошел с перевернутым индексом, как поисковая система. У вас в основном есть фиксированный словарь из 64 слов. Тогда сходство измеряется расстоянием от помех, а не косинусным сходством, которое хотела бы использовать поисковая система. Построение индекса будет медленным, но вы должны иметь возможность запрашивать его с нормальной скоростью поиска.

В книге Введение в информационный поиск раскрывается эффективное построение, хранение, сжатие и запрос инвертированных индексов.

Ответ 5

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

Этот вопрос задан раньше: Самый быстрый способ найти наиболее похожие строки для ввода?

Ответ 6

База данных/структура может быть preprocessed как , как вам нравится

Ну... IF, это правда. Тогда все, что вам нужно, это матрица сходства ваших расстояний. Сделайте матрицу разреженной путем отсечения больших расстояний. Это не получается быстрее и не так много из памяти.

Ответ 7

Ну, вы можете вставить все соседние ключи вместе с исходным ключом. Это означало бы, что вы храните (64 выбираете k) раз столько же данных, что и k разных битов, и это потребует, чтобы вы заранее определили k. Хотя вы всегда можете расширить k путем грубой силы, запрашивающей соседей, и это будет автоматически запрашивать соседние соседи, которые вы вставили. Это также дает вам компромисс между временным пространством: например, если вы принимаете 64-кратное увеличение данных и в 64 раза медленнее, вы можете получить два бита расстояния.

Ответ 8

Я не совсем об этом думал, но у меня есть идея, с чего я начну.

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

Ответ 9

Если вы в порядке с рандомизированным алгоритмом (monte carlo в этом случае), вы можете использовать minhash.

Ответ 11

Предполагая, что вам нужно посетить каждую строку, чтобы проверить ее значение (или если вы индексируете по битовому полю, а затем каждую запись индекса), вы можете достаточно эффективно написать фактический тест, используя

A xor B

Чтобы найти бит разности, затем бит-счет результата, используя технику, например this.

Это эффективно дает вам расстояние от помех.

Так как это может скомпилировать до десятков инструкций на тест, это может работать довольно быстро.

Ответ 12

Если вы в порядке с этим вероятностно, я думаю, что есть хороший способ решить вопрос 2. Я предполагаю, что у вас есть данные 2 ^ 30 и cutoff, и вы хотите найти все точки в пределах cutoff расстояние от test.

One_Try()
    1. Generate randomly a 20-bit subset S of 64 bits
    2. Ask for a list of elements that agree with test on S (about 2^10 elements)
    3. Sort that list by Hamming distance from test 
    4. Discard the part of list after cutoff

Повторяйте One_Try столько, сколько вам нужно, объединяя списки. Чем больше у вас вариантов, тем больше очков вы найдете. Например, если x находится в пределах 5 бит, вы найдете его в одной попытке с вероятностью (2/3) ^ 5 = 13%. Поэтому, если вы повторите 100 попыток, вы найдете все, кроме примерно 10 ^ {- 6} таких x. Общее время: 100*(1000*log 1000).

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

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

Ответ 13

Если данные не были настолько разреженными, граф с ключами как вершины и ребра, связывающие узлы "смежные" (Хэмминг-расстояние = 1), вероятно, были бы очень эффективными по времени. Пространство было бы очень большим, хотя, в вашем случае, я не думаю, что это было бы выгодным компромиссом.