2015-12-10 1 views
0

Я написал код для импорта xml-файла в базу данных и столкнулся с огромной проблемой производительности. Xml-файл имеет 150 Мбайт и содержит 170 000 элементов (ART) с соответствующими подэлементами (REF_DATA, ...). Мне удалось выяснить причину проблемы, но я не знаю, как ее решить.Perl XML :: LibXML очень медленная обработка из-за наклона внутри элементов

Каждый элемент ART имеет подэлементы (см. Рисунок). Проблема возникает в случае, когда у меня есть несколько подэлементов ARTPRI в ART, которые отличаются друг от друга их подэлементами PTYP. Я хотел бы, чтобы извлечь каждый ARTPRI данные/VDAT и ARTPRI/ЦЕНА и импортировать в переменные $v_dat_pexf, $v_dat_ppub, $v_dat_zurr и т.д.

Ниже минимальный пример моего кода. Этот код требует 30 секунд для чтения одного элемента ART. Когда я удаляю часть (узел START node2/END node2), xml-файл обрабатывается очень быстро (< 1s/ART).

У кого-нибудь есть идея, почему эта часть кода замедляет процесс и как справиться с этим? Спасибо за помощь.

Вот XML-файл: xml-file

И это код:

my $xml_article = "oddb_article.xml"; 
my $xpc = XML::LibXML::XPathContext->new(); 
$xpc->registerNs(sr => 'http://whatever'); 
my $doc = XML::LibXML->load_xml(location => $xml_article); 

my @node1_art = $xpc->findnodes("/sr:ARTICLE/sr:ART", $doc); 
my $i = 0; 
foreach my $node1 (@node1_art) { 
    $i++; 
    my $ref_data   = $xpc->findvalue('./sr:REF_DATA',$node1); 
    my @node1_art_artpri = $xpc->findnodes("/sr:ARTICLE/sr:ART/sr:ARTPRI", $doc); 
    my $v_dat_pexf; 

    # -- search through each ARTPRI within ART 
    # (This is the part which slows down processing) 
    # -------- START node2 ----------------------- 
    foreach my $node2 (@node1_art_artpri) { 
     my $ctrl1 = $xpc->findvalue('./sr:PTYP',$node2); 
     if ($ctrl1 eq 'PEXF') { 
     $v_dat_pexf = $xpc->findvalue('./sr:VDAT',$node2); 
     } 
    # -------- END node2 ----------------------- 
    }  
print "Row $i\n"; 
} 

Вот версия для копирования и вставки с 3 elememts АРТ:

<?xml version="1.0" encoding="utf-8"?> 
<ARTICLE xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://whatever" CREATION_DATETIME="2015-11-17T05:44:14+0100" PROD_DATE="2015-11-17T05:44:14+0100" VALID_DATE="2015-11-17T05:44:14+0100"> 
    <ART DT="" SHA256="2744a856e9bdf226e68bd555f0695b37f6477c55fca3d9eec36a0740fe8146c2"> 
    <REF_DATA>1</REF_DATA> 
    <PHAR>0000000</PHAR> 
    <SALECD>I</SALECD> 
    <CDBG>N</CDBG> 
    <BG>N</BG> 
    <DSCRD>Epimineral Paste</DSCRD> 
    <DSCRF>Epimineral pâte</DSCRF> 
    <SORTD>EPIMINERAL PASTE</SORTD> 
    <SORTF>EPIMINERAL PâTE</SORTF> 
    <ARTCOMP> 
     <COMPNO>7601003300741</COMPNO> 
    </ARTCOMP> 
    <ARTBAR> 
     <CDTYP>E13</CDTYP> 
     <BC>0</BC> 
     <BCSTAT>A</BCSTAT> 
    </ARTBAR> 
    <ARTPRI> 
     <VDAT>01.10.2015</VDAT> 
     <PTYP>PEXF</PTYP> 
     <PRICE>305.83</PRICE> 
    </ARTPRI> 
    <ARTPRI> 
     <VDAT>01.10.2015</VDAT> 
     <PTYP>PPUB</PTYP> 
     <PRICE>367.5</PRICE> 
    </ARTPRI> 
    <ARTINS> 
     <NINCD>10</NINCD> 
    </ARTINS> 
    </ART> 
    <ART DT="" SHA256="ac0eb1ad7c81f5476541ead533c48690a2c9cf3b1dd0ba8ae295145b6bcb1b40"> 
    <REF_DATA>0</REF_DATA> 
    <PHAR>0021976</PHAR> 
    <SALECD>I</SALECD> 
    <CDBG>N</CDBG> 
    <BG>N</BG> 
    <DSCRD>DIOPARINE Gtt Opht 7500 E 5 ml</DSCRD> 
    <DSCRF>DIOPARINE Gtt Opht 7500 E 5 ml</DSCRF> 
    <SORTD>DIOPARINE GTT OPHT 7500 E 5 ML</SORTD> 
    <SORTF>DIOPARINE GTT OPHT 7500 E 5 ML</SORTF> 
    <ARTCOMP/> 
    <ARTBAR> 
     <CDTYP>E13</CDTYP> 
     <BC>0</BC> 
     <BCSTAT>A</BCSTAT> 
    </ARTBAR> 
    <ARTPRI> 
     <VDAT>01.10.2015</VDAT> 
     <PTYP>PEXF</PTYP> 
     <PRICE>305.83</PRICE> 
    </ARTPRI> 
    <ARTPRI> 
     <VDAT>01.10.2015</VDAT> 
     <PTYP>PPUB</PTYP> 
     <PRICE>367.5</PRICE> 
    </ARTPRI> 
    </ART> 
    <ART DT="" SHA256="ecc62600e79183822abddb3af0d2a1f9dfb9f2c343c51a2cf135a45354ba7de1"> 
    <REF_DATA>0</REF_DATA> 
    <PHAR>0027447</PHAR> 
    <SALECD>I</SALECD> 
    <CDBG>N</CDBG> 
    <BG>N</BG> 
    <DSCRD>ARTHROSENEX Salbe 100 g</DSCRD> 
    <DSCRF>ARTHROSENEX Salbe 100 g</DSCRF> 
    <SORTD>ARTHROSENEX SALBE 100 G</SORTD> 
    <SORTF>ARTHROSENEX SALBE 100 G</SORTF> 
    <ARTCOMP/> 
    <ARTBAR> 
     <CDTYP>E13</CDTYP> 
     <BC>0</BC> 
     <BCSTAT>A</BCSTAT> 
    </ARTBAR> 
    <ARTPRI> 
     <VDAT>01.10.2015</VDAT> 
     <PTYP>PEXF</PTYP> 
     <PRICE>305.83</PRICE> 
    </ARTPRI> 
    <ARTPRI> 
     <VDAT>01.10.2015</VDAT> 
     <PTYP>PPUB</PTYP> 
     <PRICE>367.5</PRICE> 
    </ARTPRI> 
    </ART> 
    <RESULT> 
    <OK_ERROR>OK</OK_ERROR> 
    <NBR_RECORD>170673</NBR_RECORD> 
    <ERROR_CODE/> 
    <MESSAGE/> 
    </RESULT> 
</ARTICLE> 
+1

Можете ли вы предоставить минимальную структуру XML, которую мы можем скопировать/вставить, пожалуйста? Скриншот не очень полезен для попытки. – simbabque

+0

@simbabque Я добавил xml. Спасибо за ответ. – giordano

+0

Что вам нужно в результате вашего разбора? Это может быть лучше сделано с другой библиотекой. (чтобы сохранить объем памяти вниз - 'XML :: LibXML', как правило, хорош, это просто работает на целый документ) – Sobrique

ответ

3

Я думаю, что корень вашей проблемы будет состоять из комбинации этих двух линий:

my @node1_art = $xpc->findnodes("/sr:ARTICLE/sr:ART", $doc); 


my @node1_art_artpri = $xpc->findnodes("/sr:ARTICLE/sr:ART/sr:ARTPRI", $doc); 

Потому что это выглядит, как вы находите каждый ART узел через весь документ (сканирование все это), а затем для каждого такого узла - вы сканируя весь документ снова найти каждый ARTPRI узел.

Что вы тогда итерация в:

foreach my $node2 (@node1_art_artpri) { 

... но только захватывая значение последнего вы найдете.

Похоже, что это может быть логическая ошибка (трудно сказать наверняка).

Но вы пытались просто распечатывать каждый раз, когда цикл повторяется, и посмотреть, сколько раз он это делает?

Потому что это выглядит, как намерение, это только небольшое количество раз. У вас есть только два узла ARTPRI ниже вашего примера ART, но это будет делать значительно больше.

Это должно быть поправимо путем:

my @node1_art_artpri = $xpc->findnodes("./sr:ARTPRI", $node1); 

(или что-то подобное - важная часть, чтобы установить контекст узла, а не док).

Или, возможно, используя xpath вместо своего логического условия:

#!/usr/bin/env perl 

use strict; 
use warnings; 

use XML::LibXML; 

my $xpc = XML::LibXML::XPathContext->new(); 
$xpc->registerNs(sr => 'http://whatever'); 
my $doc = XML::LibXML->load_xml(location => 'test4.xml'); 

foreach my $node1 ($xpc->findnodes("/sr:ARTICLE/sr:ART", $doc)) { 
    my $ref_data = $xpc->findvalue('./sr:REF_DATA', $node1); 
    my $v_dat_pexf = 
     $xpc->findvalue('./sr:ARTPRI/sr:PTYP[text()="PEXF"]/../sr:VDAT', $node1); 
    print "$ref_data => $v_dat_pexf\n"; 
} 

Но на самом деле для такого рода задач, я мог бы думать в терминах XML::Twig, который позволяет делать вещи с помощью twig_handlers - и, таким образом, держите память ниже.

#!/usr/bin/env perl 

use strict; 
use warnings; 

use XML::Twig; 

sub extract_pexf { 
    my ($twig, $ART) = @_; 
    #or stuff it in an array, whatever. 
    print $ART -> first_child_text('REF_DATA'), " => "; 
    print $ART -> get_xpath('.//ARTPRI/PTYP[string()="PEXF"]/../VDAT',0) -> text,"\n"; 
    $twig -> purge; #clear processed data from memory. 
} 

XML::Twig -> new (twig_handlers => { 'ART' => \&extract_pexf }) -> parsefile ('your_xml'); 
+0

Вы правы! Он всегда получает одинаковое значение. – giordano

+0

Спасибо за Twig. Я попробую сначала решение для LibXML. Некоторые из того, как это должно быть возможно для цикла только в АРТ. Я нашел решение [здесь] (http://stackoverflow.com/questions/18249874/perl-xmllibxml-getting-elements-that-have-certain-attributes), но не может воспроизвести его с моим примером, вероятно, из-за пространства имен/LibXML. – giordano

+0

Причина, по которой статья не работает, заключается в том, что вы не ищете attrites, а скорее контент. Я отредактировал с примером XML: LibXML, который, как мне кажется, должен сделать трюк (работает над вырезанным образцом), но вы всегда будете иметь возможность отслеживать память. – Sobrique

Смежные вопросы