Подтвердить что ты не робот

Лучший способ быстро работать с большими объемами данных CSV

У меня есть большие наборы данных CSV (10M + lines), которые необходимо обработать. У меня есть еще два файла, на которые нужно ссылаться для вывода: они содержат данные, которые усиливают то, что мы знаем о миллионах строк в файле CSV. Цель состоит в том, чтобы вывести новый CSV файл, в который каждая запись объединена с дополнительной информацией из других файлов.

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

У коллеги есть функциональная программа, написанная на Java для этого, но она очень медленная. Причина в том, что файл CSV с миллионами строк должен проходить через много, много и много раз, очевидно.

Мой вопрос: да, я добираюсь до него - как мне подойти к этому в Ruby? Цель состоит в том, чтобы он был быстрее (18 + часов с очень небольшой активностью процессора)

Можно ли загрузить много записей в память? Если да, как мне это сделать?

Я знаю, что это немного расплывчато. Просто ищите идеи, поскольку это немного ново для меня.

4b9b3361

Ответ 1

как использовать базу данных.

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

импорт может занять некоторое время, но механизм БД будет оптимизирован для части соединения и поиска...

Ответ 2

Вот какой код ruby ​​я написал для обработки больших файлов csv (~ 180mb в моем случае).

https://gist.github.com/1323865

Стандартный FasterCSV.parse, который все это забирал в память, занимал более часа. Это дошло до 10 минут.

Соответствующая часть такова:

lines = []
IO.foreach('/tmp/zendesk_tickets.csv') do |line|
  lines << line
  if lines.size >= 1000
    lines = FasterCSV.parse(lines.join) rescue next
    store lines
    lines = []
  end
end
store lines

IO.foreach не загружает весь файл в память и просто выполняет его через буфер. Когда он достигает 1000 строк, он пытается разобрать csv и вставить только эти строки. Одна сложная часть - это "спасение". Если ваш CSV имеет несколько полей, которые охватывают несколько строк, вам может потребоваться захватить еще несколько строк, чтобы получить допустимую строку синтаксического анализа CSV. В противном случае линия, на которой вы находитесь, может находиться в середине поля.

В сущности вы можете увидеть еще одну приятную оптимизацию, которая использует обновление MySQL ON DUPLICATE KEY. Это позволяет вам вставлять массовое количество, и если обнаружен дублирующий ключ, он просто перезаписывает значения в этой строке вместо того, чтобы вставлять новую строку. Вы можете думать об этом как о создании/обновлении в одном запросе. Для этого вам нужно будет установить уникальный индекс по крайней мере для одного столбца.

Ответ 3

10M + строк на самом деле не так много. Если вы можете предварительно загрузить содержимое файлов и сопоставить данные в памяти с приличными структурами данных (в какой-то момент вам понадобятся карты), вам не придется продолжать работать через файлы CSV снова и снова. Доступ к файлу МЕДЛЕННЫЙ.

Ответ 4

Два довольно быстрых варианта:

  • Поместите свои данные в базу данных SQL. Тогда это простой запрос с парой join, который будет работать быстрее, чем все, что вы могли бы написать самостоятельно - SQL очень хорош для таких задач.

  • Предполагая, что ваши дополнительные файлы CSV достаточно малы, чтобы вписаться в ОЗУ, вы можете читать все в хэш, используя идентификатор клиента в качестве ключа, а затем искать этот хэш при обработке основного файла с помощью записей 10 + M. Обратите внимание, что только нужно поместить данные поиска в ОЗУ, основной список можно обрабатывать в небольших ветвях.

Ответ 5

Мой опыт в том, что с Ruby, подготовьтесь к использованию около 10-кратной памяти полезной нагрузки. Конечно, при текущих объемах ОЗУ, если процесс загружает только один файл за раз, 10 МБ почти пренебрежимо мал даже при умножении на десять:)

Если вы можете читать по одной строке за раз (что легко с экземплярами File), вы можете использовать FasterCSV и писать по одной строке одновременно. Это сделало бы потребление памяти O(1) вместо O(n). Но с 10-мегабайтными файлами вы, вероятно, можете разложить этот файл на память и записать его в CSV за один проход, учитывая только несколько процессов в любой момент времени.

Ответ 6

Если у вас написана Java-программа, убедитесь, что вы используете библиотеки NIO. Они быстрее, чем по умолчанию. Я уже обрабатывал текстовые файлы с 500 000 строк, используя библиотеки NIO.