Оптимизация скорости синтаксического анализа XML-файла с использованием VTD-XML - PullRequest
4 голосов
/ 14 февраля 2012

Я нахожусь в процессе анализа большого количества XML-файлов с использованием VTD-XML. Я не уверен, правильно ли я использую этот инструмент - я так думаю, но анализ файлов занимает слишком много времени.

xml-файлы (в формате DATEXII) - это сжатые файлы на HD. Распакованные они имеют размер около 31 МБ и содержат более 850 000 строк текста. Мне нужно извлечь только несколько полей и сохранить их в базе данных.

import org.apache.commons.lang3.math.NumberUtils;
...

private static void test(File zipFile) throws XPathEvalException, NavException, XPathParseException {
    // init timer
    long step1=System.currentTimeMillis();

    // open file to output extracted fragments
    VTDGen vg = new VTDGen();
    vg.parseZIPFile(zipFile.getAbsolutePath(), zipFile.getName().replace(".zip",".xml"),true);

    VTDNav vn = vg.getNav();

    AutoPilot apSites = new AutoPilot();
    apSites.declareXPathNameSpace("ns1", "http://schemas.xmlsoap.org/soap/envelope/");
    apSites.selectXPath("/ns1:Envelope/ns1:Body/d2LogicalModel/payloadPublication/siteMeasurements");
    apSites.bind(vn);

    long step2=System.currentTimeMillis();
    System.out.println("Prep took "+(step2-step1)+"ms; ");

    // init variables
    String siteID, timeStr;
    boolean reliable;
    int index, flow, ctr=0;
    short speed;
    while(apSites.evalXPath()!=-1) {

        vn.toElement(VTDNav.FIRST_CHILD, "measurementSiteReference");
        siteID = vn.toString(vn.getText());

        // loop all measured values of this measurement site
        while(vn.toElement(VTDNav.NEXT_SIBLING, "measuredValue")) {
            ctr++;

            // extract index attribute
            index = NumberUtils.toInt(vn.toString(vn.getAttrVal("index")));

            // go one level deeper into basicDataValue
            vn.toElement(VTDNav.FIRST_CHILD, "basicDataValue");

            // we need either FIRST_CHILD or NEXT_SIBLING depending on whether we find something
            int next = VTDNav.FIRST_CHILD;
            if(vn.toElement(next, "time")) {
                timeStr = vn.toString(vn.getText());
                next = VTDNav.NEXT_SIBLING;
            }

            if(vn.toElement(next, "averageVehicleSpeed")) {
                speed = NumberUtils.toShort(vn.toString(vn.getText()));
                next = VTDNav.NEXT_SIBLING;
            }

            if(vn.toElement(next, "vehicleFlow")) {
                flow = NumberUtils.toInt(vn.toString(vn.getText()));
                next = VTDNav.NEXT_SIBLING;
            }

            if(vn.toElement(next, "fault")) { 
                reliable = vn.toString(vn.getText()).equals("0");
            }

            // insert into database here...

            if(next==VTDNav.NEXT_SIBLING) {
                vn.toElement(VTDNav.PARENT);
            }
            vn.toElement(VTDNav.PARENT);
        }

    }
    System.out.println("Loop took "+(System.currentTimeMillis()-step2)+"ms; ");
    System.out.println("Total number of measured values: "+ctr);
}

Вывод точно указанной выше функции для моих XML-файлов:

Prep took 25756ms; 
Loop took 26889ms; 
Total number of measured values: 112611

В настоящий момент в базу данных фактически не вставлено никаких данных. Теперь проблема в том, что я получаю один из этих файлов каждую минуту. Общее время синтаксического анализа теперь составляет около 1 минуты, а поскольку загрузка файлов занимает около 10 секунд, и мне нужно хранить вещи в базе данных, я теперь работаю в режиме реального времени.

Есть ли способ ускорить это? То, что я пробовал, не помогло:

  • Использовать автопилоты для всех полей, это фактически замедляет второй шаг на 30000 мс
  • Разархивируйте файл и проанализируйте байтовый массив в VTD, это не имеет никакого значения
  • Зацикливать файл самостоятельно с помощью BufferedReader readLine (), но это тоже недостаточно быстро

Кто-нибудь видит возможность ускорить процесс или мне нужно начать думать о более тяжелой машине / многопоточности? Конечно, 850 000 строк в минуту (1,2 миллиарда строк в день) - это много, но я все еще чувствую, что для анализа 31 МБ данных не потребуется минуты ...

1 Ответ

1 голос
/ 06 апреля 2013

Вы можете попробовать разархивировать папку сразу и сохранить значения каждого XML-файла в массиве с

File[] files = new File("foldername").listFiles();

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

...