Как добавить данные в кучу отсортированных файлов

Прошу прощения, если это повторялось ранее, но я не смог найти ни одного поста с выбранной мною формулировкой. Я готовлюсь к интервью, и я читал о внешней сортировке. Например, если вы хотите отсортировать несколько жестких дисков с 32-битными целыми числами, вы можете выполнить сортировку подсчетом и использовать 64-битные счетчики для подсчета 32-битных целых чисел. Затем для каждого возможного 32-битного целочисленного значения у вас будет счетчик, представляющий его. Вы также можете использовать внешнюю сортировку слиянием для аналогичных вещей, занимая время O (nlogn) вместо времени O (1). Тем не менее, я думал о случае, который, вероятно, очень распространен, но я не могу придумать лучший способ сделать это - добавить новые данные в кучу отсортированных файлов, возможно, на многих жестких дисках.

Если бы данные находились в памяти, можно было бы использовать кучу (приоритетную очередь) для выполнения этой вставки за время регистрации. Однако мы не можем создать кучу из пространства на жестком диске. Со списками вам придется использовать поиск O (logn), чтобы найти место данных (для бинарного поиска, отсортированного), а затем переместить остальные данные назад или вперед, или вам может не потребоваться что-либо сдвигать в зависимости от реализации контейнера (массивы, связанные списки и т. д.). Однако в мире жестких дисков операции чтения и записи намного дороже, чем в ОЗУ, поэтому вставка данных куда-либо, а затем смещение (перезапись) остальных данных кажется непомерно дорогим. Есть ли какие-нибудь техники для этого, которые кто-нибудь из вас мог бы мне порекомендовать? Я был бы рад прочитать сам, я просто не мог найти правильный способ сформулировать свой вопрос, чтобы найти какую-либо информацию. Спасибо!


person user2045279    schedule 14.03.2013    source источник


Ответы (3)


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

Кроме того, я бы сказал, что сортировку 32-битных целых чисел лучше всего выполнять с результатом уже в виде счетчиков, особенно в очень больших масштабах, таких как «несколько жестких дисков». битовое пространство, поэтому хранение 64 бит * 2 ^ 32 может быть меньше, чем, скажем, 2 ^ 33 32-битных нулей, затем 2 ^ 32 единицы, затем...

person Vesper    schedule 14.03.2013
comment
Отличный момент! Вы кажетесь очень хорошо осведомленным, поэтому я спрошу продолжение, если вы не возражаете. Скажем, у нас есть строковые данные, максимальная длина которых не указана. Например, запись может быть Hello или fsdhgsdgghfgjdftjfhsg, длина не имеет значения. Одна запись - одна запись. Здесь мы не можем использовать счетчики, потому что создание уникального счетчика для каждой строки потребует (26 символов) ^ длины счетчиков, где длина не ограничена. Чтобы отсортировать файлы в первую очередь, мы можем использовать внешнюю сортировку слиянием, где слияние сравнивает строки в алфавитном порядке. - person user2045279; 15.03.2013
comment
Да, если вы не можете сортировать ведрами, внешняя сортировка слиянием — это то, что нужно для таких размеров данных. Кроме того, внешняя сортировка слиянием является однопроходной для предварительно отсортированных входных данных, но будет лучше на самом деле не изменять файл, который является накопителем, а вместо этого написать новый файл, затем удалить старый и переименовать новый в старый. Это ограничивает операции сортировки одной за раз, но обычно, когда вы что-то сортируете, вам нужна эксклюзивная блокировка, чтобы вы могли свободно манипулировать данными. - person Vesper; 15.03.2013
comment
Теперь вот мой актуальный вопрос: учитывая, что у меня есть несколько файлов отсортированных строк, как я могу наиболее эффективно добавить дополнительную строку? Другими словами, у меня есть масса отсортированных строк во многих файлах/дисках. У меня есть строка sdgsghdsagdf, которую я хочу добавить в хранилище. Должен ли я выполнить еще одно внешнее слияние (что займет около O (n) времени, поскольку подавляющее большинство уже отсортировано), или я должен найти, куда должна идти строка (можно использовать своего рода двоичный поиск, поскольку данные сортируются за O (logn) время.) и вставить его, а затем переписать все последующие данные? Или есть другой способ? Спасибо! - person user2045279; 15.03.2013
comment
Ооо!!!! Чтобы я мог прочитать файл, в который нужно что-то вставить, удалить этот файл, создать новый файл с новой вставкой и переименовать его в старый? Это ограничило бы нас изменением лишь небольшой части данных. Если это то, что вы говорили, то есть? - person user2045279; 15.03.2013
comment
Хм. Если вам нужно добавить одну строку, то бинарная вставка будет лучше. Если вам нужно добавить целый файл строк, внешняя сортировка слиянием будет лучше с точки зрения производительности. Но если вы планируете выполнить несколько операций вставки 1 строки, я бы сказал, что вам следует создать временный файл, который будет нормально сортироваться, а затем выполнить одно внешнее слияние. - person Vesper; 15.03.2013
comment
Хм, а можно было бы сказать Хранить все входящие вставки во временный файл. При достижении порогового размера выполните внешнее слияние всех данных и создайте новый временный файл для записи новых вставок. По сути, у нас есть этот буфер или очередь, которая захватывает новые вставки, и когда она достигает порогового значения, мы объединяемся (но тем временем новые вставки все еще могут поступать в очередь). То есть, когда очередь достигает порога, она очищается. Затем он может снова заполниться, пока пустые данные объединяются. - person user2045279; 15.03.2013
comment
Да, я так думаю. Но вам придется беспокоиться о восстановлении после сбоя при таком подходе, если вас об этом попросят. - person Vesper; 15.03.2013
comment
Ну спасибо большое, очень помогло! Теперь я думаю, что знаю, как ответить на такой вопрос, который довольно распространен в этой области (информатика/программная инженерия)! Подытожу еще одну вещь о двоичной вставке, поскольку я не думаю, что вы ответили на мое маленькое откровение: чтобы выполнить двоичную вставку, я просто нахожу файл, в который я буду вставлять новую строку, читаю этот файл в память. по частям, затем записывайте каждую часть в новый файл, вставляя новую строку туда, куда она должна идти, а затем записывая остальную часть файла. Затем удалите старый файл, замените этим новым файлом. - person user2045279; 15.03.2013
comment
Да, к сожалению, чтобы поддерживать файл SOLID с отсортированными строками, вам необходимо перезаписывать файл при каждой вставке. Но это можно как отложить, так и обойти, если у вас будет отсортированный файл с определенной внутренней структурой, которая позволит и небольшие вставки, и быструю внешнюю сортировку слиянием. Это займет некоторое время, чтобы спроектировать и реализовать это, а также больше места для хранения и обновления такого файла, но большинство перезаписей будет устранено. - person Vesper; 15.03.2013
comment
Вы очень помогли мне своими ответами, я хотел бы дать вам больше голосов. Спасибо, что уделили мне время, чтобы помочь мне во всем разобраться — на данный момент я чувствую себя довольно уверенно и планирую заняться тестовым кодированием различных вещей, которые мы обсуждали. Конечно, не на нескольких дисках, но на нескольких файлах (скажем, по 10 ГБ на штуку) это вполне разумно, поскольку это больше, чем у меня есть оперативная память. Я отметил это как ответ, и, надеюсь, это поможет кому-то еще в будущем. Еще раз спасибо, хорошего дня! - person user2045279; 15.03.2013

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

Однако в мире жестких дисков операции чтения и записи намного дороже, чем в ОЗУ, поэтому вставка данных куда-либо, а затем смещение (перезапись) остальных данных кажется непомерно дорогим.

Внешняя сортировка предназначена для случаев, когда у вас недостаточно памяти (или в большинстве случаев достаточно «на процесс»), чтобы сделать это внутри. Нередки случаи, когда наборы данных слишком велики для одновременного хранения в памяти. Таким образом, вы принимаете более высокую стоимость сортировки ввода-вывода во время выполнения.

person Randy Howard    schedule 14.03.2013
comment
Конечно, я просто ищу лучший способ вставить новые данные в уже отсортированные данные на диске, учитывая тот факт, что ввод-вывод медленный. Я сделаю еще несколько поисков по внешней сортировке, спасибо за ответ - person user2045279; 14.03.2013

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

Если вы хотите использовать тот факт, что большая часть массива уже отсортирована, и у вас есть место в памяти для этого, то сортировка вставленных элементов и объединение их со списком элементов, которые больше, чем его наименьший элемент, является хороший, быстрый способ сделать это. НАПРИМЕР:

ДИСК:

1 2 3 4 5 6 8 10 11 12

Вставки: 9 7 13

Отсортируйте вставки:

7 9 13

Найдите подмножество отсортированного списка на диске, которое подходит: 8 10 11 12

Объедините элементы в (как в Mergesort:)

7 8 9 10 11 12 13

Скопируйте их обратно на диск:

1 2 3 4 5 6 7 8 9 10 11 12 13

Если, с другой стороны, ваше пространство в памяти недопустимо меньше, чем общий размер списка, могут быть рекомендованы другие методы. Например:

1 2 3 4 .. 1000 1002 1003... 999,998, 1,000,000...

как ваш список на диске и

1001, 999,999

как ваши вставки. В этой ситуации вам нужно просмотреть каждый элемент, вычислить количество элементов в списке вставки, которые меньше этого элемента, а затем сделать это. В этом простом примере наивный счетчик работает очень быстро — вы можете видеть, что для 1 000 0000 требуется два прыжка. Если количество вставок может быть сравнительно большим, вы можете отсортировать свои вставки, а затем использовать двоичный поиск для этого элемента, чтобы найти, где может находиться каждый элемент в вашем большем массиве. Это даст вам информацию о том, сколько элементов вы можете скопировать. Таким образом, соответствующие значения прыжка для вершины будут:

0 0 0 0 ... 0 1 1 ... 1 2

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

person argentage    schedule 14.03.2013
comment
Спасибо, что нашли время ответить! - person user2045279; 15.03.2013