парсер большого xml приблизительно 300 мб

  • Автор темы Автор темы e-orel
  • Дата начала Дата начала
Возвращаюсь опять к данной теме.

<?php
$reader = new XMLReader();
$reader->open('div_kid.xml');
while ($reader->read()) {
switch ($reader->nodeType) {
case (XMLREADER::ELEMENT):


if ($reader->name == "picture")
{
$reader->read();
$picture = trim($reader->value);
// echo "$picture <br>";
break;
}

}
?>



<offer id="2304053" available="false">
<picture>1000306240.jpg</picture>
</offer>


Подскажите как мне получить значение id="2304053"
... Сижу 2 дня над этим!
Спасибо!
 
Автор оригинала: fixxxer

правильный ответ на вопрос - предложить тому, кто придумал гонять такие объемы в xml, засунуть эту xmlину себе в какое нибудь место на его усмотрение.
Это обычный прайс стандарта YML , многие магазины любят пихать товары эдак 50000 ... например, книг или дисков, вот люди, которые хотят очередной я.маркет сделать и мучаются с ними.

-~{}~ 19.03.09 11:58:

e-orel

про xml_parser_create почитайте и сделайте самостоятельно все руками, тогда не будет проблем, что, куда и откуда брать.
 
здравствуйте. у меня задача похожая, но я её вроде бы решил верно. Читаю xml-построчно. И записываю результаты в базу данных.
$reader = new XMLReader();
$reader->open($xml);
while ($reader->read()) {
и т.д.

У меня файл 200 метров. И примерно на середине парсинга этого файла скрипт просто останавливается и стоит. Никакой ошибки ничего. памяти я много выделил
ini_set("max_execution_time","9000000");
ini_set('memory_limit', '-1');

В чём тогда проблема?почему останавливается? может слишком много запросов отправляю? там не меньше 500 000 запросов получается. может БД невыдерживает?

заранее спасило за ответ.
 
DmbITpo
похоже, что-то подвисает - может, скрипт, а может и база
а ты под виндой запускаешь? кто-то проц жрет?

-~{}~ 16.06.09 11:56:

DmbITpo,e-orel
народ, расскажите, где вы такие XML по 300 метров берете?
вы вместе работаете?
 
Автор оригинала: grigori

DmbITpo,e-orel
народ, расскажите, где вы такие XML по 300 метров берете?
вы вместе работаете?
Например, прайс книжного магазина с сотней тысяч товаров...

-~{}~ 18.06.09 17:40:

DmbITpo
Сделайте лог парсинга и смотрите событие, объект и ситуацию, где виснет.

Можно прайс разбить на 2 части и парсить по очереди.
 
[off] а лучше разбирайте такие файлы perl-ом
он как-то лучше себя ведет с большими объемами [/off]
 
A1x
а лучше разбирайте такие файлы perl-ом
Тут не в перле дело, а в мозгах. Это примерно тоже что на велосипед нагрузить пару тонн груза, и потом жаловаться производителям, что-то он не едет...

Читайте файлы по кусочкам, и парсите эти кусочки... И будет всё парситься на порядок быстрее, при этом почти не занимая памяти.
 
Автор оригинала: vovanium
A1x

Тут не в перле дело, а в мозгах. Это примерно тоже что на велосипед нагрузить пару тонн груза, и потом жаловаться производителям, что-то он не едет...

Читайте файлы по кусочкам, и парсите эти кусочки... И будет всё парситься на порядок быстрее, при этом почти не занимая памяти.
Выше вроде написано, что "читаю файл построчно", само собой никто в здравом уме не запихает в память 300М, кстати построчно тоже проблема будет- результат разбора слишком большой, поэтому как вариант периодически скидывать сегменты результата, например, в файлы, а потом, после окончания разбора эти файлы заносить в базу, и тогда вам, что 10М что 500М будет одинаково.. только время работы скрипта

... хотя, если в дальнейшем результат разбора не нуждается в обработке какой то, то можно и сразу в базу скидывать
 
Есть два способа парсинга ХМL (грубо говоря)
1) когда все полностью загоняется в память, как это делают DOM и SimpleXML
2) так называемый event-driven когда ХМL читается построчно, парсер отлавливает события открытия/закрытия элемента и вызывает соответствующий обработчик, который мы на него повесили. В ПХП так работает XML Parser Functions и XMLReader

В перле есть event-driven парсер - XML::Parser
По моим сравнениям с ПХП XML Parser Functions перловский парсер показал время раза в 3 быстрее и файлы порядка 300М щелкались как орехи в плане читаем - сбрасываем в базу или в ХМL файлы меньшего размера.
Вообще имхо для работы с большими объемами данных ПХП не лучший вариант

П.С. вообще пхп люблю, так что войну можно не начинать
 
A1x, ремарка vovanium-а была не тебе, а ТС-у, потому что он как раз и пытается все в памяти обработать.
 
A1x
Моё сообщение вообще было скорее дополнением к твоему, и направлено к ТС. Которые вместо решение проблем, пытаются подобрать костыли, типа убирания ограничения по памяти и т.п.

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

Для примера, я написал парсер SQL, так вот если выключить выполнение SQL-запросов, то phpmyadmin обрабатывает дамп 250 МБ за 70 сек, мой же парсер всего за 0,7 сек (для чистоты эксперимента дамп лежал на RAM-диске, поэтому скорость упиралась, только в сам алгоритм парсинга). Т.е. на одном и том же php, скорость отличается в сотню раз.
 
vovanium
в том то и дело что мозги тут не при чем. я не знаю как насчет парсера SQL, я написал для сравнения просто скрипт, который считает количество элементов в XML, то-есть делает $n++ (без всяких мозгов) на каждое открытие тега. ПХП XML Parser Functions против perl XML::Parser - перл эту безмозглую работу делал в 3 раза быстрее чем ПХП.
Ответ же ТС - просто использовать event-driven парсинг на том языке какой он знает.
 
A1x
я не знаю как насчет парсера SQL
SQL тут не причем, это лишь пример того, что на одном и том же языке, одну и ту же задачу, можно решать с разной степенью эффективности. Аналогично и с XML.

Если несложно кидани скрипты и xml-ку на которой тестил, интересно простетить, как будет вести себя парсер на чистом php, против встроенных парсеров.
 
vovanium
скрипт на пхп из примера в мануале по XML Parser Functions - в обработчике startElement делаем просто $n++

на перле:
use XML::Parser;
my $n = 0;
my $p = new XML::Parser(Handlers => {Start => \&h_start});
$p->parsefile('t.xml');
sub h_start { $n ++ }
print $n, "\n";


ХML для испытаний (50М)
http://zero.kiev.ua/files/sxml.zip
 
ок, т.е. xml в котором вся инфа в тегах без параметров.
$n++ в принципе не особо интересно, так как в данном случае нужно сформировать из xml набор строк для загрузки в базу.
Я для теста сделал xml'ку, экспортнул таблицу с помощью phpmyadmin, получилась xml'ка 595 МБ (в файле немного больше 16 млн. строк).
Формат типа
Код:
<db>
  <table>
    <field1>Поле 1</field1>
    <field2>Поле 2</field2>
    <field_n>Поле N</field_n>
  </table>
  <table>
    <field1>Поле 1</field1>
    <field2>Поле 2</field2>
    <field_n>Поле N</field_n>
  </table>
</db>

xml_parser c пустыми функциями startElement, endElement, обрабатывает файл за 99 сек

Банальное построчное чтение с помощью
PHP:
while(fgets($x)) {}
выполняется 7 сек.

простенький парсер на чистом php который вырезает теги одной записи, т.е. то что между <table></table>, обрабатывает файл за 6,5 сек., если еще добавить преобразование этих строк в строки разделенные табуляцией (для быстрого заливания с помощью LOAD DATA), время возрастает до 9,5 сек.

В общем что и требовалось доказать, проблема этих событийных парсеров, что событий очень много в моем случае было 650 тысяч записей в бд, а xml тегов получилось больше 16 млн., учитывая что на каждый тег 2 события, получится 32 млн. вызовов функций.

На перле не пробовал пока, на этом компе не установлен, как-нибудь позже. Но быстрее работает он скорее всего только за счет другой реализации, во-первых, сам файл передается как параметр в объект, и его читает уже сам модуль, нет лишнего тягания данных, во-вторых, в парсер ты передаешь только один хендлер, а в php обязательно 2, так что вполне возможно perl экономит время на запусках закрывающего хендлера.
 
Смысл этих измерений? Понятно что просто чтение по строкам будет быстрее чем то же чтение с разбором.
Я свой тест делал для того, чтобы решить для себя стоит ли использовать пхп для разбора огромных XML файлов или нет. Потому и делал его "не особо интересным" - для чистоты эксперимента
 
A1x
Ты невнимательно читал
преобразование этих строк в строки разделенные табуляцией (для быстрого заливания с помощью LOAD DATA), время возрастает до 9,5 сек.
т.е. за 9,5 сек, из xml получается готовый результат для загрузки в базу. в случае с парсером ушло 99 секунд, даже при том что ничего не делали, т.е. быстрее 99 секунд ты с помощью парсера не сделаешь, разница на порядок.

А построчное чтение то просто для ориентира (как спичечный коробок на фотках) ;)
 
Хорошо, а что из себя представляет
простенький парсер на чистом php который вырезает теги одной записи, т.е. то что между <table></table>
?

Кстати то что в перле файл обрабатывается внутри модуля ничего не значит - модуль то тоже на перле написан. Просто перл - это Pathologically Eclectic Rubbish Lister - он изначально был заточен для перелопачивания огромных количеств непойми чего...что правда не объясняет (по крайней мере мне) почему пхп не мог бы работать так же быстро.

P.S. В пхп тоже второй хендлер можно не передавать - false вместо него
 
Сверху