Сравнение нескольких очень больших файлов csv друг с другом

#php #csv #fgetcsv

#php #csv #fgetcsv

Вопрос:

У меня есть n файлов csv, которые мне нужно сравнить друг с другом и впоследствии изменить их. Проблема в том, что каждый файл csv содержит около 800 000 строк.

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

Еще одна проблема заключается в том, что мне приходится использовать foreach для получения данных csv с помощью fgetcsv из-за количества файлов n. В итоге я получаю один сверхбольшой массив и не могу сравнить его с array_diff. Поэтому мне нужно сравнить его с вложенными циклами foreach, а это занимает целую вечность.

фрагмент кода для лучшего понимания:

 foreach( $files as $value ) {
    $data[] = $csv->read( $value['path'] );
}
  

мой класс csv использует fgetcsv для добавления выходных данных в массив:

 fgetcsv( $this->_fh, $this->_lengthToRead, $this->_delimiter, $this->_enclosure )
  

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

Теперь у меня есть этот большой массив. Обычно, если я пытаюсь сравнить значения друг с другом и выяснить, существуют ли данные из первого файла во втором файле и так далее, я использую array_diff или array_intersect . Но в этом случае у меня есть только один большой массив. И, как я уже сказал, для запуска foreach требуется время.

Также после всего 3 файлов у меня есть массив с 3 * 800.000 записей. Я думаю, что последние после 10 файлов моя память взорвется.

Итак, есть ли лучший способ использовать PHP для сравнения n очень больших файлов csv?

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

1. Обязательно ли это должен быть PHP? Может быть, есть утилита командной строки, которая делает это? Как именно вы сравниваете файлы?

2. Я программист 1980-х годов — тогда мы решили это, используя сортировку, затем некоторую логику для сравнения, затем третий файл с результатом. Несколько раз вы разбивали задание на более мелкие фрагменты, а затем запускали их последовательно. Это не решение, а способ мышления …

3. какой смысл хранить все файлы в одном массиве?

4. Мне нужно сравнить их друг с другом и сгенерировать из них новый массив, который я изменяю и отправляю через API. Итак, в конце концов, мне нужно вернуть его в PHP для API. @Col. как я уже сказал, дело в том, что я понятия не имею, как разделить его и оставаться гибким 🙂

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

Ответ №1:

Используйте SQL

  • Создайте таблицу с теми же столбцами, что и ваши файлы CSV.
  • Вставьте данные из первого файла CSV.
  • Добавьте индексы для ускорения запросов.
  • Сравните с другими файлами CSV, прочитав строку и выполнив ВЫБОР.

Вы не описали, как вы сравниваете n файлов, и есть несколько способов сделать это. Если вы просто хотите найти строку, которая находится в A1, но не в A2, …,An, тогда вам просто нужно добавить логический столбец diff в вашу таблицу. Если вы хотите знать, в каких файлах строка повторяется, вам понадобится текстовый столбец или новая таблица, если строка может быть в нескольких файлах.

Редактировать: несколько слов о производительности, если вы используете MySQL (я сейчас мало что знаю о других СУБД).

Вставка строк одна за другой будет слишком медленной. Вы, вероятно, не сможете использовать LOAD DATA , если не сможете поместить файлы CSV непосредственно в файловую систему сервера БД. Поэтому я думаю, что лучшим решением будет прочитать несколько сотен строк в CSV, а затем отправить запрос с несколькими вставками INSERT INTO mytable VALUES (..1..), (..2..) .

Вы не можете выдавать a SELECT для каждой строки, которую вы читаете в других файлах, поэтому вам лучше поместить их в другую таблицу. Затем выполните обновление для нескольких таблиц, чтобы отметить строки, которые идентичны в таблицах t1 и t2: UPDATE t1 JOIN t2 ON (t1.a = t2.a AND t1.b = t2.b) SET t1.diff=1

Может быть, вы могли бы попробовать использовать sqlite. Здесь нет проблем с параллелизмом, и это может быть быстрее, чем модель клиент / сервер MySQL. И вам не нужно много настраивать, чтобы использовать sqlite.

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

1. Спасибо. Мне нужно сравнить, находится ли A1 в файле 2/3/4 в любой позиции и так далее. Я думаю, я попробую с временной базой данных

2. Да, я использую LOAD DATA для импорта csv. Он все еще медленный, но пока все в порядке. Спасибо, чувак.