Методы работы с «тяжёлыми» 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=date
    • 5 июня 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, а не simplexml
            • 5 июня 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, на втором уже зная ее обрабатываем последовательно блоки.

© Habrahabr.ru