Нужен способ сортировки файла журнала 100 GB по дате [закрыто]

Итак, по какой-то странной причине я заканчиваю с файлом журнала 100GB, который несортирован (на самом деле он частично отсортирован), в то время как алгоритмы, которые я пытаюсь применить, требуют сортировки данных. Строка в файле журнала выглядит так

data <date> data data more data

у меня есть доступ к C# 4.0 и около 4 ГБ ОЗУ на моей рабочей станции. Я бы предположил, что слияние-какой-то вид будет лучше всего здесь, но за исключением реализации этих алгоритмов самостоятельно - я хочу спросить, есть ли какой-то вид я могу срезать путь.

кстати разбор строки даты с DateTime.Parse() очень медленно и занимает много времени процессора -урчание-скорость мизерная 10 МБ / сек. Есть ли более быстрый способ, чем следующий?

    public static DateTime Parse(string data)
    {            
        int year, month, day;

        int.TryParse(data.Substring(0, 4), out year);
        int.TryParse(data.Substring(5, 2), out month);
        int.TryParse(data.Substring(8, 2), out day);

        return new DateTime(year, month, day);
    }

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

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

Я ищу толчок в правильном направлении, спасибо заранее.

редактировать: некоторые люди предложили использовать сравнение строк для сравнения дат. Это будет работать на этапе сортировки, но мне нужно проанализировать даты для алгоритмов. Я до сих пор не знаю, как сортировать файл 100GB на 4GB бесплатной оперативной памяти, не делая этого вручную.

правка 2: ну, благодаря нескольким предложениям, которые я использую окна вроде, я узнал, что есть аналогичный инструмент для Linux. В основном вы называете сортировку, и она все исправляет для вас. Как мы говорим, это делает что-то, и я надеюсь, что это скоро закончат. Команду я использую это

sort -k 2b 2008.log > 2008.sorted.log

- k указывает, что я хочу отсортировать во второй строке, которая является строкой даты и времени в обычном . Должен признать, что man-страницам не хватает, чтобы объяснить все варианты, но я нашел много примеров, запустив info coreutils 'sort invocation'.

я сообщу результаты и тайминги. Эта часть журнала составляет около 27GB. Я думаю о сортировке 2009 и 2010 отдельно, а затем объединить результаты в один файл с опцией sort-M.

Edit 3 Ну, проверка iotop предполагает, что это чтение в небольших кусках данных файл, а затем яростно что-то делать, чтобы обработать их. Этот процесс кажется довольно медленным. =(

sort не использует никакой памяти и только одно ядро. Когда он читает данные с диска, он ничего не обрабатывает. Я делаю что-то не так?

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

изменить 5 прежде чем я пошел домой, я перезапустил процесс со следующей командой:

sort -k 2b --buffer-size=60% -T ~/temp/ -T "/media/My Passport" 2010.log -o 2010.sorted.log

он вернулся сегодня утром:

sort: write failed: /media/My Passport/sortQAUKdT: File too large

Wraawr! я думал, что просто добавлю как можно больше жестких дисков, чтобы ускорить этот процесс. По-видимому, добавление USB-накопителя было худшей идеей. В момент я даже не могу сказать, о FAT / NTFS или о чем-то таком, потому что fdisk говорит мне, что USB-накопитель - "неправильное устройство"... без шуток. Я попробую дать ему еще один шанс позже, а теперь давайте положим этот проект в возможно провалившуюся кучу.

Окончательное Уведомление На этот раз он работал с той же командой, что и выше, но без проблемного внешнего жесткого диска. Спасибо всем за помощь!

бенчмаркинг

через 2 класс рабочей станции (по крайней мере, 70 Мб/сек чтение/запись IO) жесткие диски на том же контроллере SATA, мне потребовалось 162 минуты для сортировки файла журнала 30GB. Мне нужно будет отсортировать еще один файл 52 GB сегодня вечером, я опубликую, как это происходит.

16 ответов


Если сортировка строк будет работать для вас, просто используйте команду сортировки Windows. Сортируйте файл и покончите с этим. Он с удовольствием отсортирует ваш файл 100GB, и он прост в использовании.

Если вам нужно отфильтровать и преобразовать файл, в частности поле даты, то я бы просто написал небольшую программу преобразования, которая преобразует поле данных в 0 заполненное целое число (например, # секунд с 1970 года или что угодно), и переписывает запись. Затем вы можете передать (|) вывод в команда сортировки, то у вас есть окончательный, отсортированный файл, который более легко анализируется вашей служебной программой.

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

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

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

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

убедитесь, что ваша информация о дате, если вы решили использовать целое число, имеет все поля одинаковой длины. В противном случае утилита сортировки не будет сортировать их правильно (вы получите 1 10 2 3 вместо 1 2 3 10. Ты лучше 01 02 03 10.).

изменить --

давайте подойдем к нему от a другой такт.

большой вопрос "вам нужны все эти данные". Это относится к более раннему предложению о том, чтобы сначала выполнить тяжелый синтаксический анализ. Очевидно, чем больше вы можете уменьшить начальный набор, тем лучше. Например, простое удаление 10% данных составляет 10 ГБ.

то, о чем мне нравится думать, как правило, особенно при работе с большим количеством данных: "если у вас есть 1 миллион чего-то, то каждая сэкономленная миллисекунда составляет 20 минут от дна линия."

обычно мы действительно не думаем с точки зрения миллисекунд для нашей работы, это больше "место штанов", "что чувствует себя быстрее". Но 1ms = = 20min/million-хорошая мера, чтобы понять, сколько данных вы имеете дело и сколько времени должно / может занять.

для вас случай, 100GB данных. С swag 100 байтов на запись, вы берете 1 миллиард строк. 20,000 минут в миллисекунды. -- 5 с половиной часов. залпом (это эмпирическое правило, если вы сделайте математику, это не совсем работает для этого.)

таким образом, вы можете оценить желание уменьшить необработанные данные, если это вообще возможно.

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

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

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

сколько деталей вам действительно нужно? И сколько информации вы отслеживаете? Например, если бы это была, скажем, веб-статистика, у вас на сайте могло бы быть 1000 страниц. Но даже с почасовой оплатой в течение года, 365 * 24 * 1000, это всего лишь 8.7 м "ведра" информации - далеко от 1B.

Итак, есть ли какая-либо предварительная обработка, которую вы можете сделать, не требующая сортировки? Обобщение информации в более грубую гранулярность? Вы можете сделать это без сортировки, просто используя хэш-карты на основе памяти. Даже если у вас нет "достаточной памяти" для обработки всех 100 ГБ данных за один бросок, у вас, вероятно, есть достаточно, чтобы сделать это кусками (5 кусков, 10 кусков) и записать промежуточные результаты.

У вас также может быть намного больше удачи в разделении данных. В ежемесячные или еженедельные куски файлов. Возможно, это нелегко сделать, потому что данные "в основном" отсортированы. Но в этом случае, если это по дате, преступники (т. е. данные, которые не в порядке) могут хорошо быть кластеризованным в файле, с" не по порядку " вещи просто смешиваются на барьерах периодов времени (например, вокруг дневных переходов, возможно, у вас есть строки, как 11:58pm, 11:59pm, 00:00am, 00:01am, 11:58pm, 00:02pm). Возможно, вы сможете использовать и эту эвристику.

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

Итак, эти тактики можно взять к проблеме. Обобщение, очевидно, является лучшим, поскольку все, что уменьшает эту нагрузку на данные в любом измеримом, вероятно, стоит проблем. Конечно, все сводится к тому, что вы действительно хотите от данных, ясно, что отчеты будут управлять этим. Это также хороший момент о " pre-mature оптимизация." Если они не сообщают об этом, не обрабатывайте его :).


такой код полностью связан с тем, как быстро вы можете получить данные с диска. Файл просто никогда не может поместиться в кэше файловой системы, поэтому вы всегда ждете на диске, чтобы предоставить данные. Вы делаете довольно хорошо на 10 МБ / сек, оптимизация кода никогда не будет иметь заметного эффекта.

получить более быстрый диск. Дефрагментируйте тот, который у вас есть в качестве промежуточного шага.


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


Почему бы вам не попробовать этот относительно неизвестный инструмент от microsoft под названием С помощью средства LogParser. Он в основном позволяет выполнять SQL-запрос через CSV-файл (или любой другой форматированный текстовый файл).

избавляет вас от необходимости перекачивать его в базу данных, делать свой вид и откачивать его снова


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

  • разделите вход на несколько частей, которые вписываются в память и могут быть отсортированы с помощью стандартных алгоритмов сортировки в памяти (например, 100 Мб или больше-вам нужно будет сохранить ~4 части в памяти сразу). Отсортируйте все части и запишите их обратно диск.

  • прочитайте две части с диска (они оба отсортированы) и объедините их, что можно сделать, одновременно повторяя два входа. Напишите объединенный набор данных в другое место на диске. Обратите внимание, что вам не нужно читать весь часть в память-просто прочитайте его / напишите его в блоках, как вы идете.

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

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


лучший способ оптимизации разбора дат-это вообще не разбирать их.

Как даты в формате ISO 8601, вы можете просто сравнить их как строки. Разбор не требуется вообще.

Что касается сортировки, вы должны иметь возможность эффективно использовать тот факт, что он частично отсортирован. Одним из подходов может быть чтение файла и запись в отдельные файлы, разделенные по временным диапазонам, например, ежедневно или ежечасно. Если вы сделаете каждый файл достаточно маленьким, вы можете затем прочитайте их в память и отсортируйте, а затем просто объедините все файлы.

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


для сортировки вы можете реализовать сортировку на основе файлов:

  1. открыть входной файл
  2. читать файл строка за строкой
  3. узнать дату как строку из строки
  4. добавить строку в файл <date>.log

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

оставшейся задачей будет сортировка созданных файлов и, возможно, снова объедините файл.


мне нужно проанализировать даты для алгоритмов.

On * NIX, я обычно сначала преобразовывал даты во что-то простое, подходящее для сравнения текста, и делал это первым словом в строке. Слишком рано для создания объекта даты / времени. Моя обычная презентация даты YYYYMMDD-hhmmss.millis. Сделайте так, чтобы все файлы имели одинаковый формат даты.

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

Как вы уже поняли, сортировка слиянием является единственным вариантом.

Итак, для меня задачи попадают в следующий шаг:

  1. стремно преобразование, чтобы сделать даты сортировки. Сложность: чтение / запись последовательно 100GB.

  2. разделите данные на куски полезного размера, например 1GB, и отсортируйте каждый кусок, используя простую быструю сортировку перед записью на диск. Сложность: чтение / запись последовательно 100GB; память для быстрая сортировка.

  3. сортировка слиянием мелких файлов в один большой. Это можно сделать поэтапно, используя программу, которая берет два файла и объединяет их в новый. Сложность: чтение / запись последовательно 100Gb log (N) раз (где N-количество файлов). Требование к космосу HDD: 2 * 100GB (последнее слияние 2 файлов x 50GB в одиночный файл 100GB).

  4. программа для автоматизации предыдущего шага: выберите два (например, самые маленькие) файла, запустите программу для сортировки-объедините их в новый файл удалите два исходных файла. Повторяйте до тех пор, пока количество файлов не превысит 1.

  5. (необязательно) разделите отсортированный файл 100GB на более мелкие куски управляемого размера. В конце концов, вы собираетесь что-то с ними сделать. Пронумеруйте их последовательно или поместите метки первого и последнего времени в имя файла.

общая концепция: не пытайтесь найти способ сделать это быстро, трубопровод 100GB в любом случае займет время; план для программ один каждый шаг, чтобы запустить в течение ночи, как партия, без вашего внимания.

на Linux, что все выполнимо с shell/sort/awk / Perl, и я не думаю, что это проблема, чтобы написать все это на любом другом языке программирования. Это потенциально 4 программы , но все они довольно просты в коде.


предполагая, что ваш файл журнала имеет только 1-2% строк не в порядке, вы можете сделать один проход через полный журнал, опережая два файла: один файл, который находится в порядке, и другой файл, содержащий 1-2% строк, которые не в порядке. Затем отсортируйте неупорядоченные строки в памяти и выполните одно слияние ранее неупорядоченных строк со строками в порядке. Это будет намного быстрее, чем полное слияние, которое сделает намного больше проходов.

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


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

  1. база данных с индексом в столбце Дата (чтобы быть легко найти в этих данных после).
  2. для вставки в эту базу используйте Bulk Insert.
  3. и какой-то способ параллельного чтения (в think parallel LINQ был бы хорош и очень прост в использовании).
  4. много терпения (самое главное/трудная вещь)

упреждающий комментарий: Мой ответ касается только подзадачи разбора значений времени даты.

DateTime.Parse содержит проверки всех возможных форматов дат. Если у вас есть формат fix, вы можете оптимизировать синтаксический анализ довольно хорошо. Простая оптимизация заключалась бы в непосредственном преобразовании символов:

class DateParserYyyyMmDd
{
    static void Main(string[] args)
    {
        string data = "2010-04-22";

        DateTime date = Parse(data);
    }

    struct Date
    {
        public int year;
        public int month;
        public int day;
    }

    static Date MyDate;

    static DateTime Parse2(string data)
    {
        MyDate.year = (data[0] - '0') * 1000 + (data[1] - '0') * 100 
            + (data[2] - '0') * 10 + (data[3] - '0');
        MyDate.month = (data[5] - '0') * 10 + (data[6] - '0');
        MyDate.day = (data[8] - '0') * 10 + (data[9] - '0');

        return new DateTime(MyDate.year, MyDate.month, MyDate.day);
    }
}

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


на самом деле не решение, но просто из интереса, один из способов сделать это так:

  • сначала разбейте файл на файлы 1GB
  • затем, читая 2 файла за раз, загрузите содержимое в список строк и отсортируйте его
  • записать его обратно в отдельные файлы.

проблема в том, что вам нужно будет прочитать/записать 100 файлов на каждом проходе и сделать 100 проходов, чтобы убедиться, что данные отсортированы.

Если моя математика правильно: то есть 10 000 ГБ чтения и 10 000 ГБ записи, в среднем 10 МБ / сек, что составляет 20 000 000 сек, что 231 дней

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


вы можете попробовать реализовать алгоритм сортировки radix. Поскольку radix сканирует весь список последовательно и только несколько раз, это может помочь здесь предотвратить гигантское количество сканирований и запросов вашего файла 100 GB.

сортировка Radix предназначена для классификации записей каждой итерации по одной части. Эта часть может быть цифрой или дату как год, месяц, день. в этом случае вам даже не нужно преобразовывать строку в DateTime, вы можете преобразовать только определенную часть в int.

Edit:

для целей сортировки вы можете создать временный двоичный файл только с 2 столбцами: DateTime (DateTime.ToBinary () как Int64) и адрес строки в исходном файле (как Int64).

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

после завершения сортировки временного файла вы можете создать обратно полный сортированный журнал 100 ГБ файл.


Вау. Во-первых, это совершенно новый уровень документирования-obssession.

мой фактический edvice будет, попробуйте рассмотреть, насколько необходим этот файл на самом деле.

о сортировке, я понятия не имею, будет ли это работать или нет, но вы можете попытаться построить перечислитель, который возвращает данные непосредственно с жесткого диска (не сохраняя ничего, кроме нескольких указателей, возможно), а затем пытается использовать OrderBy LINQ, который также возвращает IEnumerator, который вы, надеюсь, можете Enamurate и сохранить непосредственно обратно на диск.

единственный вопрос заключается в том, сохраняет ли OrderBy что-либо в ОЗУ.


загрузите вкус Linux с USB И используйте команду while для чтения Папка. Используйте команды grep, фильтры и Каналы для разделения данных. Все это можно сделать в 3 строки сценария BASH. Grep будет разрывать данные в Никакое время. Я grepped через 7 миллионов строк за 45 секунд