Warning: Cannot use a scalar value as an array in /home/admin/public_html/forum/include/fm.class.php on line 757
Warning: Invalid argument supplied for foreach() in /home/admin/public_html/forum/include/fm.class.php on line 770
Warning: Invalid argument supplied for foreach() in /home/admin/public_html/forum/topic.php on line 737 Форумы портала PHP.SU :: Как парсить большие XML-файлы
Этот участок кода, у меня занимает полминуты. Ведь в функции _custom_function_save_current_param() я должен сначала сделать проверку, а не существует ли такой param-объект в таблице, записать если надо, потом в отдельной таблице (связь many-to-many) записать связь между offer_id и param_id.
Короче мой парсер точно захлебнётся с большим XML-файлом. Как на практике парсить разумно? Частями?
Покинул форум
Сообщений всего: 10377
Дата рег-ции: Дек. 2008 Откуда: Альфа Центавра
Помог: 353 раз(а)
Да, читаешь файл кусками, ищешь там метку "<offer", по ней разбиваешь на маленькие файлы, потом натравливаешь свой импортер на эти файлы. После успешного импорта удаляешь эти временные файлы.
Покинул форум
Сообщений всего: 80
Дата рег-ции: Апр. 2012
Помог: 0 раз(а)
DeepVarvar пишет:
Да, читаешь файл кусками, ищешь там метку "<offer", по ней разбиваешь на маленькие файлы, потом натравливаешь свой импортер на эти файлы. После успешного импорта удаляешь эти временные файлы.
Мне прочитать каждый кусок файла с offer и затем создать мини-файл, например, в папке tmp? Я пока не знаю как это реализовать в коде, но разве так парсер не захлебнётся?
Да, сейчас попробую сделать так, как вы советуете с Эстерио.
MiksIr пишет:
XMLReader не читает весь файл в память. Он оперирует курсором, указывающим на текущее положение в файле и операции сдвига курсора.
А со временем у него в другом месте проблема, тут хоть кусками, хоть не кусками.
Ты же видишь что я читаю offer классом XMLElementIterator - это уже не чистый XMLReader (это я сейчас тыкаю пальцем в небо). Иначе прочитать параметры продукта я не смог.
Покинул форум
Сообщений всего: 378
Дата рег-ции: Сент. 2014
Помог: 10 раз(а)
[+]
Вот этим? https://github[dot]com/hakre/XMLReaderIterator
Нужно смотреть как сделано, но он вроде использует XMLReader, т.е. читать весь файл не должен. Тестировали на больших файлах потребление памяти?
А проблема времени, как я понял, больше от базы данных зависит. Нужно смотреть, что там сделать можно, если время критично. Я бы пошел путем загрузки всего этого во временную таблицу, а потом уже синхронизацию с основной таблицей несколькими SQL запросами.
----- self-banned
esterio
Отправлено: 30 Апреля, 2015 - 15:37:51
Активный участник
Покинул форум
Сообщений всего: 5025
Дата рег-ции: Нояб. 2012 Откуда: Украина, Львов
Помог: 127 раз(а)
MiksIr пишет:
а потом уже синхронизацию с основной таблицей несколькими SQL запросами.
или INSERT ... SELECT
MiksIr
Отправлено: 30 Апреля, 2015 - 15:45:36
Забанен
Покинул форум
Сообщений всего: 378
Дата рег-ции: Сент. 2014
Помог: 10 раз(а)
[+]
esterio пишет:
MiksIr пишет:
а потом уже синхронизацию с основной таблицей несколькими SQL запросами.
или INSERT ... SELECT
Нужно еще удалять и обновлять. Если в случае mysql добавление и обновление еще можно совместить, то удаление - все-равно отдельный запрос.
----- self-banned
Faab
Отправлено: 30 Апреля, 2015 - 16:45:30
Гость
Покинул форум
Сообщений всего: 80
Дата рег-ции: Апр. 2012
Помог: 0 раз(а)
Да, конечно я использую временные таблицы.
Большого файла нет: увеличил свой файл до 3,500 товаров методом копи-паст.
При оригинальном коде, у меня выдало ошибку "Fatal error: Maximum execution time of 30 seconds exceeded" уже когда в базу записался 150-ый товар. Время работы скрипта: 4 минуты.
Когда я подправил свою функцию _custom_function_save_current_param(), а именно убрал проверку, связную таблицу, так что бы напрямую записывался каждый объект параметра при вызове функции, то теперь у меня сгенерировалась ошибка "Fatal error: Maximum execution time of 30 seconds exceeded" только уже когда в таблице было записано 672 товара (это 20102 параметра).
Последний вариант у меня занял 7 минут, и то, учитывая что у меня в локальном php.ini прописано следующее:
max_execution_time = 0 ; Maximum execution time of each script, in seconds
max_input_time = 0 ; Maximum amount of timeeach script
На хостинге прописать такое как вы понимаете трудно.
Тут как не крути надо пробовать вариант преложенный Esterio и DeepVarvar.
MiksIr
Отправлено: 30 Апреля, 2015 - 16:48:50
Забанен
Покинул форум
Сообщений всего: 378
Дата рег-ции: Сент. 2014
Помог: 10 раз(а)
[+]
Думаю, сначала стоит заняться профайлингом, что бы понять - где теряется время.
Второе - такие вещи нужно запускать и консоли, а не через веб.
Ну и третье - сохранять состояние после каждой операции, что бы повторный запуск продолжал работу, а не начинал сначала.
----- self-banned
Faab
Отправлено: 30 Апреля, 2015 - 16:55:38
Гость
Покинул форум
Сообщений всего: 80
Дата рег-ции: Апр. 2012
Помог: 0 раз(а)
MiksIr пишет:
Думаю, сначала стоит заняться профайлингом, что бы понять - где теряется время.
Второе - такие вещи нужно запускать и консоли, а не через веб.
Ну и третье - сохранять состояние после каждой операции, что бы повторный запуск продолжал работу, а не начинал сначала.
На счёт третьего: так может и сделать ограничение на чтение только 50 товаров за один запуск скрипта? После чтения 50 продукта установить cron, что бы через две-три минуты запустить этот же скрипт.
Я пока не знаю как перейти к чтению именно мне нужного продукта, но думаю это можно реализовать.
Все гости форума могут просматривать этот раздел. Только зарегистрированные пользователи могут создавать новые темы в этом разделе. Только зарегистрированные пользователи могут отвечать на сообщения в этом разделе.