Методы работы с «тяжёлыми» XML
Комментарии (22)
5 июня 2017 в 14:50
+2↑
↓
Ваш тест производительности опровергает ваши же утверждения о медлительности DOM и SimpleXML по сравнению с XMLReader. И еще бы не плохо показать объем используемой памяти.5 июня 2017 в 14:54
0↑
↓
да, последнюю цифру не правильно скопировал.
ок, добавлю данные по используемой памяти
5 июня 2017 в 14:56
–7↑
↓
какими средствами лучше разбирать объёмный XML
Во первых надо отказаться от формата и переходить на json в любом случае.
Во вторых получать ленту со стороны сервера уже обработанную, по параметрам.
? part=snippet, contentDetails&maxResults=15&order=date5 июня 2017 в 14:57
+2↑
↓
К сожалению наши поставщики прайс-листов не хотят переходить на параметры и отдают нам XML от 500 до 1500 Mb.5 июня 2017 в 16:02
0↑
↓
В принципе даже simplexml_load_file можете разбить на блоки, как вот товарищ пишет, он через curl/
Но вот как обрабатывает ошибки json.Есть же какие то программы, которые конвертируют файл на стороне клиента, только конвертация уменьшит его размер на треть.
$json = curl_exec($ch); if ($json !== false) { //решаем проблему ошибок $json = preg_replace("#(/\*([^*]|[\r\n]|(\*+([^*/]|[\r\n])))*\*+/)|([\s\t]//.*)|(^//.*)#", '', $json); setlocale(LC_ALL, 'ru_RU.utf8'); Header("Content-Type: text/html;charset=UTF-8"); curl_close($ch); $json = json_decode($json, true) ;
5 июня 2017 в 16:09
0↑
↓
Не так давно пришлось изменять целый модуль после старого программиста, именно из-за его идеи разбивать файл на кучу новых по 30 Mb и разбирать всё это дело через simplexml. Такой утечки памяти добился он что сервер не мог выдержать 100 человек онлайн.5 июня 2017 в 16:37
+1↑
↓
Можно парсить на сущности (теги), используя XMLReader, а затем эту сущность разбирать уже через DomDocument. Таким образом, памяти будет кушать не много, а DomDocument куда более приятен и расширяем, хотя, конечно, по скорости будет чуть медленнее.А вообще, такие парсеры лучше писать на более шустрых комилируемых языках, к примеру go. Там это в разы будет быстрее работать и можно использовать конкурентные вычисления, писать порциями напрямую в базу. Вы удивитесь насколько это будет шустрее работать и памяти жрать будет в разы меньше
6 июня 2017 в 01:17
0↑
↓
А как можно обработать большой json (к примеру > 100 мб)? Если вот нужно, и никак иначе? Буду признателен за ответ
5 июня 2017 в 15:01
+2↑
↓
Помимо времени выполнения следовало бы замерить использованную память.
5 июня 2017 в 15:42 (комментарий был изменён)
+1↑
↓
У меня тоже есть поставщики фидов по 2–4 gb на xmlМне пришлось написать безумные вещь для этой задачи.
— Открываю файл и читаю его построчно, пропуская открытие и закрытие, беру около 300 000 строк
— При помощи CURL рассылаю строки на эту же машину + на удаленные машины (24 запроса = 300 000/24)
— Все 24 запроса конвертируют XML в key/value массив
— Система собирает с каждого curl один массивИ так по кругу пока не кончится файл
Из сложного — надо правильно открывать и закрывать xml, чтобы он был валидный.
PS.
24 — это не сервера, это запросы, сервернов 4 по 6 (6 ядрен * на 4 офисные машины)Проверьте htop, ваш php для этой задачи берет скорее всего только 1 ядро, заставить брать все ядра можно мультизапросами.
5 июня 2017 в 15:48
0↑
↓
Уточняю— Все 24 запрсоа не только конвертируют XML → В массив, естественно они сначала конвертируют строки в XML объект. Но так как по XML объект ходить сложно (особенно, когда структура постоянно разная), то я написал функцию конвертации всех параметрво и аттрибутов в key/value массив, который возращается как json
— 24, 300 000 — все эти цифры условные, постоянно перенастраиваются и тд
5 июня 2017 в 16:11
–1↑
↓
Почитайте мой верхний комментарий.
Из-за таких способов происходит дикая утечка памяти, т.к. вы грузите по 300 000 строк, в то время когда воспользовавшись XMLReader или xml_parser вы будете тратить максимум 1 мегабайт памяти.
P.S. на разбор файла в 1.5 Gb уходит 7 Mb памяти и около 1.5 часа. Это учитывая что кроме разбора файла идёт множество mysql запросов5 июня 2017 в 16:16 (комментарий был изменён)
+1↑
↓
За что минусуют не могу понять, у меня на разбор уходет от 5 до 15 минут на 7gb xml данных, а у вас 1.5 часа на 1.5Дикая утечка памяти? Авто же жаловался на скорость, зачем мне экономить память, и это не утечка, а использование. Моя задача скорость и я разбил файл на 300 000 кусков и разослал на обработку 6 серверам всем их ядрам под 100%.
Зачем это делать на сервере с онлайн пользователями — я не понимаю)
XMLReader или xml_parser — я жду их выполнения, что мне толку от их потребления памяти, памяти в избытке, а 300 000 строк по кругу не позволяют ей выйти из того объема, который меня устраивает. Если их же вызвать 24 раза одновременно — будет в 24 раза быстрее, а 300 000/24 — парсер не каждую строчку конвертирует, а все строчки как 1 файл на ядре.
5 июня 2017 в 16:19
0↑
↓
А завтра поменяют разбиение XML-файла на строки и все у вас упадет.
5 июня 2017 в 16:26
+1↑
↓
Нет, я не конвертирую строки, я на 1 ядре объединяю их и делаю из них валидный xml, потому не важно как именно разбит файл, идея считывать группу строк, а не весь файл целиком.Все упадет если файл будет 1 строковый. Ну под это тоже можно написать альтернативу, но по задаче не требуется.
5 июня 2017 в 16:35
0↑
↓
А как вы будете разбивать файл вот такого формата?
Item 1 Item 2 Item 3 Item 4 Item 5 5 июня 2017 в 23:32 (комментарий был изменён)
0↑
↓
По строкам, а потом допишу в разрыве xml, чтобы превратить в валидный, чтобы не потерять данные, следующий цикл начнется на пару строк выше разрыва, есть вероятность повтороного попадания данных (дубли), но они пропускаются при импортеНужно просто очистить хвост, чтобы в конце остался только закрывающийся тег
5 июня 2017 в 16:19
0↑
↓
Это время и память на работу на 1 сервере.
По факту вы делаете кучу лишней работы которая не нужна.
Возможно конкретно в вашем случае это помогло решить какие-то другие задачи, но в целом даже на обработке 300 000 строк я бы использовал xml_reader, а не simplexml5 июня 2017 в 16:21 (комментарий был изменён)
0↑
↓
Ну это моя проблема выбора, конвертора, я лишь описал как я ускорил, если xml_reader лучше, то в данном случае он тоже отработает хорошо.
5 июня 2017 в 16:35
–1↑
↓
Долго. Хотя, если такое время выполнения никому неудобств не доставляет — ну ладно.
Но, в любом случае, насилие БД… Вы при разборе каждого узла делаете запросы? У вас при разборе файла какие запросы превалируют: INSERT или UPDATE? Что, если собирать данные и отправлять их в БД пачками (bulk insert), т.е., вместо 100/200/500 запросов сделать 1? Или возможно, если вы используете innodb и у вас autocommit=1 (по умолчанию), а вы и не знали?5 июня 2017 в 16:47
0↑
↓
Оптимизация базы проведена.
Используются транзакции.
Большие запросы вынесены в отдельный файл который работает с очередью RabbitMQ
5 июня 2017 в 16:41
+1↑
↓
Была задача распарсить многогиговые XML файлы, делал очень просто, зная структуру XML файла читал построчно, последовательно заполняя и обрабатывая объектную модель. При незнакомом формате, можно в два прохода, на первом строит схему XML, на втором уже зная ее обрабатываем последовательно блоки.