Каков наилучший способ перебора и обработки большого (10 ГБ ) текстового файла?

#python #mysql #parsing #scripting #large-files

#python #mysql #синтаксический анализ #сценарии #большие файлы

Вопрос:

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

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

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

Комментарии:

1. Форматируются ли данные как JSON?

2. Файл зоны отформатирован так, как указано в RFC 1035, en.wikipedia.org/wiki/Zone_file

Ответ №1:

У вас не должно возникнуть никаких реальных проблем с хранением такого объема данных в MySQL, хотя вы, вероятно, не сможете сохранить всю базу данных в памяти, поэтому ожидайте некоторых проблем с производительностью ввода-вывода. Как всегда, перед выполнением запросов убедитесь, что у вас есть соответствующие индексы.

Самое главное — не пытаться загрузить весь файл в память целиком. Перебирайте файл, не пытайтесь использовать такой метод, как readlines, который загрузит весь файл сразу.

Обязательно выполняйте пакетные запросы. Загружайте несколько тысяч строк за раз и отправляйте их все в одном большом SQL-запросе.

Такой подход должен сработать:

 def push_batch(batch):
    # Send a big INSERT request to MySQL

current_batch = []
with open('filename') as f:
    for line in f:
        batch.append(line)

        if len(current_batch) > 1000:
            push_batch(current_batch)
            current_batch = []

    push_batch(current_batch)
 

Файлы зон довольно нормально отформатированы, подумайте, можете ли вы обойтись простым использованием файла LOAD DATA INFILE. Вы также можете рассмотреть возможность создания именованного канала, ввода в него частично отформатированных данных из python и использования LOAD DATA INFILE для их чтения с помощью MySQL.

В MySQL есть несколько отличных советов по оптимизации вставок, некоторые основные моменты:

  • Используйте несколько списков значений в каждом операторе insert.
  • Используйте ЗАДЕРЖКУ ВСТАВКИ, особенно если вы отправляете запросы от нескольких клиентов одновременно (например, с использованием потоков).
  • Заблокируйте свои таблицы перед вставкой.
  • Настройте key_buffer_size и bulk_insert_buffer_size .

Самая быстрая обработка будет выполняться в MySQL, поэтому подумайте, сможете ли вы выполнить необходимые запросы после того, как данные будут в БД, а не раньше. Если вам действительно нужно выполнять операции на Python, потоковая обработка вам не поможет. Одновременно может выполняться только один поток кода Python (GIL), поэтому, если вы не делаете что-то, что тратит значительное количество времени на C, или не взаимодействуете с внешними ресурсами, вы все равно будете работать только в одном потоке.

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

Комментарии:

1. Здесь действительно ценная информация, Зак, спасибо! После того, как я проанализирую и сохраню данные, я собираюсь запустить список регулярных выражений для каждой записи и выполнить несколько сетевых запросов (ping и т. Д.). Я собираюсь сделать это в отдельном скрипте, и я не уверен, что Python будет наиболее оптимальным для этого — мне сказали, что C будет лучше.

2. @MarathonStudios Python подойдет, поскольку основная часть времени, затрачиваемого на такие операции, как ping, приходится на ожидание сетевых запросов. Это было бы время, когда использование нескольких потоков было бы очень ценным. Создайте несколько threading.Queue зон для тестирования, пул потоков, которые извлекают запись из очереди, проверяют ее и сохраняют результаты, и один или несколько потоков, которые запрашивают в БД несколько десятков еще непроверенных записей и добавляют их в очередь. Настройте количество загружаемых и потребляющих потоков для оптимизации производительности.

3. Регулярные выражения @MarathonStudios также были бы хороши, поскольку фактическая реализация в модуле re в любом случае находится на C. Сначала убедитесь, что вы скомпилировали выражения ( docs.python.org/library/re.html#re.compile ), так что его не нужно переделывать для каждой записи. Однако обратите внимание, что MySQL поддерживает регулярные выражения ( dev.mysql.com/doc/refman/5.1/en/regexp.html ), и все, что делается в БД, как правило, будет быстрее, чем внешняя программа (используйте инструкции UPDATE).

Ответ №2:

Ответ @ Zack Bloom отличный, и я поддержал его. Всего пара мыслей:

  • Как он показал, with open(filename) as f: for line in f все, что вам нужно сделать, это просто использовать / . open() возвращает итератор, который выдает вам по одной строке за раз из файла.
  • Если вы хотите вставить каждую строку в свою базу данных, сделайте это в цикле. Если вам нужны только определенные строки, соответствующие определенному регулярному выражению, это просто.
 импорт повторно

 pat = re.compile(some_pattern)

 с open(filename) как f:
для строки в f:
если не pat.search (строка):
 продолжить
 # проделайте работу, чтобы вставить строку здесь
  • С файлом размером в несколько гигабайт вы, вероятно, будете привязаны к вводу-выводу. Так что, вероятно, нет причин беспокоиться о многопоточности или о чем-то еще. Даже выполнение нескольких регулярных выражений, вероятно, приведет к обработке данных быстрее, чем файл может быть прочитан или обновлена база данных.
  • Лично я не большой специалист по базам данных, и мне нравится использовать ORM. В последнем проекте, над которым я работал с базой данных, я использовал Autumn с SQLite. Я обнаружил, что по умолчанию ORM должен был выполнять один коммит на вставку, и на вставку множества записей уходила вечность, поэтому я расширил Autumn, чтобы позволить вам явно заключать в скобки кучу вставок одним коммитом; так было намного быстрее. (Хм, я должен расширить Autumn для работы с with инструкцией Python, чтобы вы могли обернуть кучу вставок в with блок, и Autumn автоматически зафиксирует.)

http://autumn-orm.org/

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