Поиск наборов, которые имеют определенные подмножества

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

Мои данные по существу состоят из большого количества наборов чисел. Эти наборы могут содержать от 1 до n чисел внутри себя (хотя в 99,9% наборов n меньше 15), и таких наборов примерно 1,5 ~ 2 миллиарда (к сожалению, такой размер исключает перебор).

Мне нужно иметь возможность указать набор из k элементов и вернуть мне каждый набор из k+1 элементов или более, содержащий указанное подмножество.

Простой пример:
Предположим, у меня есть следующие наборы данных:
(1,2,3)
(1,2,3,4,5)
(4,5,6, 7)
(1,3,8,9)
(5,8,11)

Если бы я дал запрос (1,3), у меня были бы наборы: (1,2,3), (1,2,3,4,5) и (1,3,8,9).< br> Запрос (11) вернет набор: (5,8,11).
Запрос (1,2,3) вернет наборы: (1,2,3) и (1,2, 3,4,5)
Запрос (50) не вернет наборов:

К настоящему времени узор должен быть четким. Основное различие между этим примером и моими данными заключается в том, что наборы с моими данными больше, числа, используемые для каждого элемента наборов, варьируются от 0 до 16383 (14 бит), и есть еще множество наборов.

Если это имеет значение, я пишу эту программу на C++, хотя я также знаю java, c, немного ассемблера, немного фортрана и немного perl.

Кто-нибудь знает, как это осуществить?

редактировать:
Чтобы ответить на пару вопросов и добавить несколько моментов:

1.) Данные не меняются. Все это было снято за одну длинную серию прогонов (каждый из которых был разбит на 2 гигабайтных файла).

2.) Что касается места для хранения. Необработанные данные занимают примерно 250 гигабайт. По моим оценкам, после обработки и удаления большого количества посторонних метаданных, которые мне не интересны, я могу сократить их до 36–48 гигабайт в зависимости от того, сколько метаданных я решу сохранить (без индексов). Кроме того, если при первоначальной обработке данных я столкнусь с достаточным количеством одинаковых наборов, я смогу еще больше сжать данные, добавив счетчики для повторяющихся событий, а не просто повторяя события снова и снова.

3.) Каждое число в обрабатываемом наборе фактически содержит как минимум два числа: 14 бит для самих данных (обнаруженная энергия) и 7 бит для метаданных (номер детектора). Так что мне потребуется как минимум три байта на число.

4.) Мой комментарий «хотя в 99,9% наборов n меньше 15» вводил в заблуждение. При предварительном просмотре некоторых фрагментов данных я обнаружил, что у меня есть наборы, содержащие до 22 чисел, но медиана составляет 5 чисел на набор, а среднее значение — 6 чисел на набор.

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

6.) Что касается доступных мне ресурсов, я могу собрать около 300 гигабайт пространства после того, как у меня будут необработанные данные в системе (оставшаяся часть моей квоты в этой системе). Система представляет собой двухпроцессорный сервер с 2 четырехъядерными процессорами AMD и 16 гигабайтами оперативной памяти.

7.) Да 0 может возникнуть, это артефакт системы сбора данных, но это может произойти.


person James Matta    schedule 30.01.2009    source источник
comment
Как часто базовые данные меняются, если вообще меняются? Если он не подлежит изменению, есть способы впечатляюще ускорить поиск с помощью небольшой предварительной обработки (своего рода индексации), но это само по себе займет некоторое время.   -  person paxdiablo    schedule 30.01.2009
comment
Кроме того, каковы ваши ограничения на хранение? Я знаю способ сделать поиск очень быстрым, но мы говорим о начальной оценке требуемой 3800G, не обязательно в одной файловой системе. Опять же, это зависит от динамики данных.   -  person paxdiablo    schedule 30.01.2009
comment
2 миллиарда наборов из шести 2-байтовых чисел и близко не заполняют 250 ГБ, в десять раз. Похоже, ваше хранилище данных в настоящее время очень неэффективно.   -  person Sparr    schedule 31.01.2009
comment
Это данные из Гаммасферы, в которых содержится неимоверное количество метаданных. Двухбайтовое число, на которое я ссылаюсь, — это номер канала детектора, единственные метаданные, которые мне нужны, — это номер детектора, связанный с ним, но есть и много других вещей.   -  person James Matta    schedule 31.01.2009
comment
Кроме того, хранение данных не может быть столь же эффективным, как оптимальное решение, потому что все наборы перемешаны друг с другом, поэтому для разделения данных требуется много информации в заголовке. Заголовки для событий составляют, может быть, 10% или пространство.   -  person James Matta    schedule 31.01.2009
comment
Метаданные для каждого события составляют примерно 80% пространства, а сами числа в наборах занимают примерно 10% пространства. Дело не в том, что формат хранения данных неэффективен, я просто описал только самое необходимое из того, что было в необработанных данных.   -  person James Matta    schedule 31.01.2009
comment
И все метаданные также служат цели для разных стилей экспериментов или для разных форм анализа данных, просто на текущем этапе анализа они мне не нужны, и ответ не зависит от них, поэтому я отказался от них. phy.anl.gov/gammasphere/doc/index.html   -  person James Matta    schedule 31.01.2009


Ответы (6)


Ваша проблема такая же, как и у поисковых систем. «У меня миллиард документов. Мне нужны те, которые содержат этот набор слов». У вас просто (очень удобно) целые числа вместо слов и маленькие документы. Решением является инвертированный индекс. Введение в поиск информации Мэннинга и др. (по адресу эта ссылка) доступна бесплатно в Интернете, очень удобочитаема и содержит множество подробностей о том, как это сделать.

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

person Jay Kominek    schedule 30.01.2009
comment
Единственное, что следует добавить, это то, что у Мэннинга и др. есть глава о сжатии индексов, которая здесь очень уместна — не пропустите ее. - person SquareCog; 30.01.2009
comment
Спасибо за ссылку на книгу, я прочитал часть онлайн-версии, и она мне понравилась настолько, что я ее заказал. Он идет рядом с «Искусством компьютерного программирования» Кнута, «Языком программирования C++» Страуструпа и «Стандартной библиотекой шаблонов» Джоссуттиса. Мои основные ссылки. - person James Matta; 30.01.2009
comment
Если вы в настроении читать, вы также можете заглянуть на этот: портал. acm.org/citation.cfm?doid=1132956.1132959 - person SquareCog; 30.01.2009

Предполагая случайное распределение 0-16383, с постоянными 15 элементами в наборе и двумя миллиардами наборов, каждый элемент будет появляться примерно в 1,8 млн наборов. Рассматривали ли вы (и есть ли у вас возможности) создание таблицы поиска размером 16384x~1,8M (30 Б записей, по 4 байта каждая)? Имея такую ​​таблицу, вы можете запросить, какие наборы содержат (1), (17) и (5555), а затем найти пересечения этих трех списков из ~1,8 млн элементов.

person Sparr    schedule 30.01.2009
comment
Я не совсем уверен, что справочная таблица - это то, что нужно, сами необработанные данные занимают примерно 265 гигабайт, после первоначальной обработки они займут, возможно, 230~250 гигабайт (необработанный формат тратит место и содержит много посторонней информации). ), поэтому размер таблицы будет вдвое меньше данных. - person James Matta; 30.01.2009
comment
Хотя, если честно, мне пришел в голову индекс поиска, и если ничего лучшего не будет предложено, вероятно, это будет мой метод с индексом к индексу, чтобы я мог переходить в нужные места в индексе. - person James Matta; 30.01.2009

Моя догадка такова.

Предположим, что у каждого набора есть имя, идентификатор или адрес (4-байтовое число подойдет, если их всего 2 миллиарда).

Теперь пройдитесь по всем наборам один раз и создайте следующие выходные файлы:

  • Файл, содержащий идентификаторы всех наборов, содержащих «1».
  • Файл, содержащий идентификаторы всех наборов, содержащих «2».
  • Файл, содержащий идентификаторы всех наборов, содержащих «3».
  • ... и т.д ...

Если в наборе 16 записей, то в среднем каждый из этих 2^16 файлов будет содержать идентификаторы 2^20 наборов; с каждым идентификатором, равным 4 байтам, для этого потребуется 2 ^ 38 байт (256 ГБ) хранилища.

Вы сделаете это один раз перед обработкой запросов.

При получении запросов используйте эти файлы следующим образом:

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

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

person ChrisW    schedule 30.01.2009

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

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

http://www.ddj.com/184410998
и
http://www.dcs.bbk.ac.uk/~jkl/publications.html< /а>

person James Matta    schedule 11.09.2009

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

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

Если ваши значения распределены равномерно, каждый индексный файл будет содержать 1/16383 входных наборов. Если ваш средний поисковый набор состоит из 6 значений, вы будете выполнять линейный проход по 6/16383 вашего исходного ввода. Это все еще решение O(n), но ваше n теперь немного меньше.

P.S. Является ли ноль невозможным значением результата или у вас действительно есть 16384 возможностей?

person Mark Ransom    schedule 30.01.2009
comment
Я вижу, что вы уже выбрали другое решение, пока я думал об этом. Ну что ж. - person Mark Ransom; 30.01.2009
comment
Что ж, ваше решение очень похоже на то, которое я выбрал, и книга, которую рекомендовал Джей, заполняет несколько пробелов в обоих методах, теперь я просто думаю о способах уменьшения размера данных и индексов. какая-то структура, которая может убрать часть избыточности в данных. - person James Matta; 30.01.2009
comment
Да, в самом деле. 0 действительно возникает, это артефакт системы сбора данных, но он возникает. Какое-то ненулевое значение приходит по трубе, но на него наложено вето чем-то, что предотвращает прохождение нежелательных сигналов. К сожалению, если скорость счета высока, иногда записывается результирующий ноль. - person James Matta; 30.01.2009

Просто играю в адвоката дьявола для подхода, который включает в себя грубую силу + поиск по индексу:

  1. Создайте индекс с min , max и no элементов наборов.
  2. Затем примените грубую силу, исключая наборы, где max ‹ max (искомый набор) и min > min (искомый набор).
  3. При грубой силе также исключаются наборы, количество элементов которых меньше, чем в искомом наборе.

95% ваших поисков действительно были бы перебором с очень меньшим подмножеством. Просто мысль.

person Learning    schedule 30.01.2009
comment
Подмножество будет меньше, но почему вы думаете, что оно будет намного меньше в 95% случаев? Я предполагаю, что обычно вы исключаете только около 75% из 2 миллиардов наборов, что все равно оставляет слишком много. - person ChrisW; 30.01.2009