2012-04-05 4 views
2

내 목표는 25GB의 XML 데이터를 구문 분석하는 것입니다. 이러한 데이터의 예는 아래와 같습니다 :25GB 데이터에 대한 효율적인 XML 구문 분석

<Document> 
<Data Id='12' category='1' Body="abc"/> 
<Data Id='13' category='1' Body="zwq"/> 
. 
. 
<Data Id='82018030' category='2' CorrespondingCategory1Id='13' Body="pqr"/> 

내가 "25기가바이트"의이 데이터를 However..considering ... 내 접근 방식은 매우 비효율적이다. 제 코드를 개선하거나 다른 방법을 제안하십시오. 또한 사물을 더 명확하게 만들기 위해 작은 예제 코드를 포함하십시오.

+0

가능한 [Python sax에서 80x1GB XML 용 lxml]의 복제본 (http://stackoverflow.com/questions/9809469/python-sax-to-lxml-for-80gb-xml) –

답변

4

SAX 파서가이 작업에 더 잘 작동하는 경우가 있습니다. SAX 파서는 DOM을 구축하는 대신 XML 파일을 요소 스트림으로 전환하고 각 요소를 처리 할 수 ​​있도록 제공하는 함수를 호출합니다.

좋은 점은 DOM 파서에 비해 SAX 파서가 매우 빠르고 메모리 효율이 높으며 모든 XML을 한 번에 가져올 필요가 없기 때문에 25GB의 그것. 당신이 좋아하는 어떤 컨텍스트 정보를 필요로하는 경우

불행하게도, "나는 태그 <B>을 원하지만 내부 태그 <A>의 경우에만,"모든 파서가, 태그 <A> 시작 태그 <B>을 시작하면 "입니다 제공하기 때문에 당신은 스스로를 유지해야 끝 태그 <B>, 끝 태그 <A>. " 태그 <B><A> 태그 안에 있다고 명시 적으로 알려주지는 않는다면, 본 것으로부터 알아 내야합니다. 그리고 일단 요소를 보았다면, 당신이 그것을 기억하지 않는 한 사라졌습니다.

이것은 복잡한 구문 분석 작업에서 매우 털이 나지 만, 당신은 아마도 관리 할 수 ​​있습니다.

파이썬의 표준 라이브러리에 SAX 파서가 xml.sax 인 경우가 있습니다. 아마도 xml.sax.xmlreader.IncrementalParser과 같은 것을 원할 것입니다.

+0

도움에 감사드립니다. 작은 예제 코드로 개념을 설명해 주실 수 있습니까? 그것은 정말로 당신의 종류 일 것입니다 ... 당신은 자신의 간단한 예제도 만들 수 있습니다. –

+0

기회가 생기면 그럴 것입니다. 그래도 나는 시간을 가질 것이다. – kindall

0

내 질문에 대한 첫 번째 제안은 MySQL 또는 sqlite와 같은 관계형 데이터베이스를 사용하는 것입니다. XML 데이터를이 형식으로 변환하는 것은 어렵지 않을 것입니다. 그런 다음 해당 데이터를 쿼리하는 것이 더 쉽고 빠릅니다.

+0

나는 원하지 않는다. 그 접근법을 취하는 것 ... 근본적으로 25GB의 데이터를위한 테이블 조인은 많은 시간이 필요합니다. 따라서 ... 나는 자체적으로 파싱을하는 대안을 찾고있다. –

+0

이 많은 데이터로 여기에서 만드는 쿼리의 종류에 대해서는 실제로 데이터베이스가 필요하다. 인덱스를 올바르게 정의하면 제안한 것보다 훨씬 빠르고 * 빠릅니다. 따라서 SAX 또는 기타 증분 파서를 사용하여 데이터를 데이터베이스에로드 한 다음 데이터베이스에서 쿼리하여 새 XML 파일에 기록하십시오. –

0

초기 알고리즘은 O (n^2)로 실행되며, 25GB의 데이터에는 매우 느립니다. 이상적으로는 O (n) 또는 O (n log n)까지 가져올 것입니다. 이 없지만

from lxml import objectify 
f=open('myfile25GB', 'r') 
text=f.read() 
root=objectify.fromstring(text) 

cat_one_bodies = {} 
for e in root.attrib['Document'].row: 
    category = int(e.attrib['category']) 
    body = e.attrib['Body'] 
    if category == 1: 
     e_id = int(e.attrib['Id']) 
     cat_one_bodies[e_id] = body 
    else: #Assuming there are only 2 categories 
     cat_one_id = int(e.attrib['CorrespondingCategory1Id']) 
     print "Cat1 Body: '%s' Cat2 Body: '%s'" % (body, cat_one_bodies[cat_one_id]) 

: (카테고리 1 또는 2 작은 여부 등 등) 데이터에 대한 다른 정보가없는 경우, 당신은 ((n)이 O입니다) 같은 것을 할 수 있습니다 귀하의 파일을 구문 분석, 잘하면 그것은 당신에게 아이디어를 보여줍니다. 잠재적으로 상당히 많은 메모리를 사용합니다 (사전의 모든 category1 본문을 유지 관리하므로). 다음과 같이

0
XSLT 3.0로 현재 색슨-EE 구현 (안)에서

,이 문제를 해결 스트리밍 변환을 작성할 수 있습니다

<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:map="http://www.w3.org/2005/xpath-functions/map"> 
<xsl:mode streamable="yes"/> 
<xsl:template match="/"> 
    <xsl:iterate select="Document/Data"> 
    <xsl:param name="map" select="map{}"/> 
    <xsl:choose> 
     <xsl:when test="@category='1'"> 
     <xsl:next-iteration> 
      <xsl:with-param name="map" select="map:put($map, string(@Id), string(@Body))"/> 
     </xsl:next-iteration> 
     </xsl:when> 
     <xsl:otherwise> 
     <xsl:value-of select="'Cat1 Body: ', 
           $map(@CorrespondingCategoryId), 'Cat2 Body', @Body"/> 
     </xsl:otherwise> 
    </xsl:choose> 
    </xsl:iterate> 
</xsl:template> 

내가이 시험하지 않았다 (그것의 늦은 밤에 4 일간의 휴일 전야에 ...)하지만이 접근법을 추구하는 데 관심이 있다면 기꺼이 도와 드리겠습니다. XSLT 3.0은 아직 초안 사양이며 상당히 유동적입니다. 초점은 바운드 메모리를 사용하여 매우 큰 문서를 처리하는 스트리밍 방식을 사용하는 것과 같은 문제를 해결하는 데 있습니다. Saxon-EE 9.4는 스펙의 스냅 샷을 구현합니다.

+0

꽤 멋져 보입니다. – kindall

0

ID가 오름차순이면 파일의 어느 위치에서나 요소를 읽는 자체 함수를 롤아웃 할 수 있습니다.그런 다음 전체 파일을 스캔 할 수 있으며 모든 요소에 대해 이진 검색 알고리즘을 사용하여 해당 요소를 찾을 수 있습니다. 문제는 여전히 무시할만한 양의 메모리를 사용하면서 O (n log n)에서 실행됩니다.

0

lxml의 iterparse를 사용해보십시오. 나는 그것이 당신이 다루고 자하는 문제에 맞을 것이라고 생각합니다.

+0

여기에 비슷한 질문이 .iterparse()에 의해 해결되었습니다 http://stackoverflow.com/a/9814580/1346705 – pepr