Алгоритмы поиска подстроки (очень большой стог сена, маленькая игла)

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

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

Я нашел алгоритмы, которые занимают O (n) время ( n = размер стога сена, м ] = размер иглы), и наивный поиск занимает O (n + m) . Поскольку m в этом конкретном случае будет очень маленьким, есть ли другой алгоритм, на который я мог бы обратить внимание?

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

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

Я нашел алгоритмы, которые занимают O (n) время ( n = размер стога сена, м ] = размер иглы), и наивный поиск занимает O (n + m) . Поскольку m в этом конкретном случае будет очень маленьким, есть ли другой алгоритм, на который я мог бы обратить внимание?

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

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

Я нашел алгоритмы, которые занимают O (n) время ( n = размер стога сена, м ] = размер иглы), и наивный поиск занимает O (n + m) . Поскольку m в этом конкретном случае будет очень маленьким, есть ли другой алгоритм, на который я мог бы обратить внимание?

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

Я нашел алгоритмы, которые занимают O (n) времени ( n = размер стога сена, m = размер иглы), и наивный поиск занимает ] O (N + M) . Поскольку m в этом конкретном случае будет очень маленьким, есть ли другой алгоритм, на который я мог бы обратить внимание?

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

Я нашел алгоритмы, которые занимают O (n) времени ( n = размер стога сена, m = размер иглы), и наивный поиск занимает ] O (N + M) . Поскольку m в этом конкретном случае будет очень маленьким, есть ли другой алгоритм, на который я мог бы обратить внимание?

Редактировать: Спасибо всем за ваши предложения! Еще немного информации - Данные могут рассматриваться как случайные биты, поэтому я не думаю, что возможна какая-либо индексация / сортировка. Данные для поиска могут быть чем угодно, не английскими словами или чем-либо предсказуемым.

9
задан Dogbert 8 August 2010 в 22:50
поделиться

5 ответов

Вы ищете структуру данных, которая называется Trie или «префиксное дерево». Короче говоря, эта структура данных кодирует все возможные префиксы строк, которые можно найти в вашем корпусе.

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

Если вам известен определенный предел длины входной строки поиска, вы можете ограничить рост вашего Trie, чтобы он не сохранял префиксы, длина которых превышает эту максимальную длину. Таким образом, вы можете уместить Trie, представляющее все 10 ГБ, в менее чем 10 ГБ памяти. Любой тип Trie представляет собой сжатое представление данных, особенно для часто повторяющихся данных. (Или должно быть , если реализовано разумно.) Ограничение глубины Trie до максимальной строки поиска ввода позволяет вам еще больше ограничить потребление памяти.

7
ответ дан 4 December 2019 в 12:58
поделиться

Стоит взглянуть на массивы суффиксов и деревья . Оба они требуют предварительных вычислений и значительного объема памяти, но они лучше, чем обратные индексы в том смысле, что вы можете искать произвольные подстроки в O (m) (для суффиксных деревьев) и O (m + log n) (для массивов суффиксов с наименьшей общей префиксной информацией).

Если у вас есть много времени, вы можете изучить сжатые массивы суффиксов и сжатые CSA, которые представляют собой сжатые версии ваших данных, которые также являются самоиндексирующимися ( т.е. данные также являются индексом, внешнего индекса нет).Это действительно лучший из миров, потому что у вас есть не только сжатая версия ваших данных (вы можете выбросить исходные данные), но она также проиндексирована! Проблема состоит в том, чтобы понять исследовательские работы и перевести их в код :)

Если вам не нужно идеальное сопоставление подстрок, а скорее общие возможности поиска, ознакомьтесь с Lucene .

3
ответ дан 4 December 2019 в 12:58
поделиться

Если вы можете позволить себе место (много места!) Для создания индекса, вам определенно стоит индексировать небольшие фрагменты (например, четырехбайтовые блоки) и хранить их вместе с их смещения в стоге сена - тогда поиск 10 байтов включает поиск всех четырех байтовых блоков для первых четырех байтов поискового запроса и проверку следующих шести байтов.

0
ответ дан 4 December 2019 в 12:58
поделиться

Учитывая Кнута – Морриса – Пратта или Бойера – Мура, вы не добьетесь большего успеха, поэтому вам следует подумать о распараллеливании процесса поиска.

3
ответ дан 4 December 2019 в 12:58
поделиться

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

Но вот другая идея, которая прибегает к фильтрам Блума. Вы, вероятно, знаете, что это такое, но на всякий случай (и для других людей, читающих этот ответ): Фильтры Блума - это очень маленькие, очень компактные битовые векторы, которые аппроксимируют включение множества. Если у вас есть множество S и фильтр Блума для этого множества B(S), то

x ∈ S ⇒ x ∈ B(S)

но обратное утверждение будет ложным. Вот что является вероятностным в этой структуре: существует (количественно измеримая) вероятность того, что фильтр Блума вернет ложное срабатывание. Но аппроксимация включения с помощью фильтра Блума дико быстрее, чем его точное тестирование на множестве.

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

Фильтры Блума с некоторым успехом использовались в строковом поиске. Вот набросок (возможно, я неправильно помню некоторые детали) этого применения. Текстовый файл представляет собой последовательность из N строк. Вы ищете слово, состоящее из M букв (причем ни одно слово не может быть разнесено на две строки). На этапе предварительной обработки будет создан ОДИН фильтр Блума для каждой строки, путем добавления каждой подпоследовательности строки в фильтр Блума; например, для этой строки

 Touching this dreaded sight, twice seene of vs,

И соответствующий фильтр Блума будет создан с "T", "To", "Tou" .... "o", "ou", ... "vs,", "s", "s,", ",". (Я могу ошибаться в этой части. Или вы можете захотеть оптимизировать.)

Затем при поиске подслова размером M просто сделайте одну очень быструю проверку каждого из фильтров Блума, и когда есть совпадение, внимательно изучите строку, например, с помощью алгоритма KMP. На практике, если вы хорошо настроите свои фильтры Блума, компромисс будет замечательным. Поиск становится невероятно быстрым, потому что вы удаляете все бесполезные строки".

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

  • либо разрезать набор данных на множество блоков размером K (каждый со своим фильтром Блума, как строки в предыдущем примере);

  • либо использовать своего рода дихотомию, когда вы разбиваете набор на два подмножества, каждое из которых имеет фильтр Блума, затем каждое подмножество разбивается на два подмножества со своим фильтром Блума и т. д. (если вы собираетесь добавить все подстроки, как это предлагается в описанном мной методе, эта вторая идея будет немного запретительной - за исключением того, что вам не нужно добавлять все подстроки, а только подстроки размером от 1 до 10).

Обе идеи могут быть объединены изобретательными способами для создания многоуровневых схем.

3
ответ дан 4 December 2019 в 12:58
поделиться
Другие вопросы по тегам:

Похожие вопросы: