парсер большого 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 дня над этим!
Спасибо!
 

Andre

Новичок
Автор оригинала: fixxxer

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

-~{}~ 19.03.09 11:58:

e-orel

про xml_parser_create почитайте и сделайте самостоятельно все руками, тогда не будет проблем, что, куда и откуда брать.
 

DmbITpo

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

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

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

заранее спасило за ответ.
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
DmbITpo
похоже, что-то подвисает - может, скрипт, а может и база
а ты под виндой запускаешь? кто-то проц жрет?

-~{}~ 16.06.09 11:56:

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

Andre

Новичок
Автор оригинала: grigori

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

-~{}~ 18.06.09 17:40:

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

Можно прайс разбить на 2 части и парсить по очереди.
 

A1x

Новичок
[off] а лучше разбирайте такие файлы perl-ом
он как-то лучше себя ведет с большими объемами [/off]
 

vovanium

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

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

Andre

Новичок
Автор оригинала: vovanium
A1x

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

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

... хотя, если в дальнейшем результат разбора не нуждается в обработке какой то, то можно и сразу в базу скидывать
 

A1x

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

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

П.С. вообще пхп люблю, так что войну можно не начинать
 

dimagolov

Новичок
A1x, ремарка vovanium-а была не тебе, а ТС-у, потому что он как раз и пытается все в памяти обработать.
 

vovanium

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

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

Для примера, я написал парсер SQL, так вот если выключить выполнение SQL-запросов, то phpmyadmin обрабатывает дамп 250 МБ за 70 сек, мой же парсер всего за 0,7 сек (для чистоты эксперимента дамп лежал на RAM-диске, поэтому скорость упиралась, только в сам алгоритм парсинга). Т.е. на одном и том же php, скорость отличается в сотню раз.
 

A1x

Новичок
vovanium
в том то и дело что мозги тут не при чем. я не знаю как насчет парсера SQL, я написал для сравнения просто скрипт, который считает количество элементов в XML, то-есть делает $n++ (без всяких мозгов) на каждое открытие тега. ПХП XML Parser Functions против perl XML::parser - перл эту безмозглую работу делал в 3 раза быстрее чем ПХП.
Ответ же ТС - просто использовать event-driven парсинг на том языке какой он знает.
 

vovanium

Новичок
A1x
я не знаю как насчет парсера SQL
SQL тут не причем, это лишь пример того, что на одном и том же языке, одну и ту же задачу, можно решать с разной степенью эффективности. Аналогично и с XML.

Если несложно кидани скрипты и xml-ку на которой тестил, интересно простетить, как будет вести себя парсер на чистом php, против встроенных парсеров.
 

A1x

Новичок
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
 

vovanium

Новичок
ок, т.е. 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 экономит время на запусках закрывающего хендлера.
 

A1x

Новичок
Смысл этих измерений? Понятно что просто чтение по строкам будет быстрее чем то же чтение с разбором.
Я свой тест делал для того, чтобы решить для себя стоит ли использовать пхп для разбора огромных XML файлов или нет. Потому и делал его "не особо интересным" - для чистоты эксперимента
 

vovanium

Новичок
A1x
Ты невнимательно читал
преобразование этих строк в строки разделенные табуляцией (для быстрого заливания с помощью LOAD DATA), время возрастает до 9,5 сек.
т.е. за 9,5 сек, из xml получается готовый результат для загрузки в базу. в случае с парсером ушло 99 секунд, даже при том что ничего не делали, т.е. быстрее 99 секунд ты с помощью парсера не сделаешь, разница на порядок.

А построчное чтение то просто для ориентира (как спичечный коробок на фотках) ;)
 

A1x

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

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

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