Leyendo un archivo XML enorme usando StAX y XPath

El archivo de entrada contiene miles de transacciones en formato XML que tiene un tamaño de alrededor de 10 GB. El requisito es elegir cada XML de transacción en función de la entrada del usuario y enviarlo al sistema de procesamiento.

El contenido de muestra del archivo

<transactions>
    <txn id="1">
      <name> product 1</name>
      <price>29.99</price>
    </txn>

    <txn id="2">
      <name> product 2</name>
      <price>59.59</price>
    </txn>
</transactions>

Se espera que el usuario (técnico) dé el nombre de la etiqueta de entrada como <txn>.

Nos gustaría ofrecer esta solución para que sea más genérica. El contenido del archivo puede ser diferente y los usuarios pueden dar una expresión XPath como "//transactions/txn"para elegir transacciones individuales.

Hay algunas cosas técnicas que tenemos que considerar aquí.

  • El archivo puede estar en una ubicación compartida o FTP
  • Dado que el tamaño del archivo es enorme, no podemos cargar el archivo completo en JVM

¿Podemos usar el analizador StAX para este escenario? Tiene que tomar la expresión XPath como entrada y elegir / seleccionar XML de transacción.

Buscando sugerencias. Gracias por adelantado.

preguntado el 27 de agosto de 11 a las 16:08

Mi recomendación es usar vtd-xml extendido en modo de mapa de memoria y jvm de 64 bits -

7 Respuestas

Si el rendimiento es un factor importante y / o el tamaño del documento es grande (ambos parecen ser el caso aquí), la diferencia entre un analizador de eventos (como SAX o StAX) y la implementación nativa de Java XPath es que este último compila un documento DOM del W3C antes de evaluar la expresión XPath. [Es interesante notar que todas las implementaciones del Modelo de Objetos de Documento de Java como DOM o Axiom usan un procesador de eventos (como SAX o StAX) para construir la representación en memoria, así que si alguna vez puedes arreglártelas solo con el procesador de eventos, estás ahorrando tanto la memoria como el tiempo que lleva construir un DOM.]

Como mencioné, la implementación de XPath en el JDK opera sobre un documento DOM de W3C. Puede ver esto en la implementación del código fuente de Java JDK mirando com.sun.org.apache.xpath.internal.jaxp.XPathImpl, donde antes de que se llame al método evalu (), el analizador primero debe analizar la fuente:

  Document document = getParser().parse( source );

Después de esto, sus 10 GB de XML se representarán en la memoria (más los gastos generales), probablemente no sea lo que desea. Si bien es posible que desee una solución más "genérica", tanto su XPath de ejemplo como su marcado XML parecen relativamente simples, por lo que no parece haber una justificación realmente sólida para un XPath (excepto quizás elegancia de programación). Lo mismo sería cierto para la sugerencia de XProc: esto también construiría un DOM. Si realmente necesita un DOM, puede usar Axiom en lugar del W3C DOM. Axiom tiene una API mucho más amigable y construye su DOM sobre StAX, por lo que es rápido y usa Jaxen para su implementación XPath. Jaxen requiere algo tipo de DOM (W3C DOM, DOM4J o JDOM). Esto será cierto para todas las implementaciones de XPath, por lo que si realmente no necesita que XPath se quede solo con el analizador de eventos, se recomienda.

SAX es la antigua API de transmisión, con StAX más nueva y mucho más rápida. Ya sea utilizando la implementación nativa de JDK StAX (javax.xml.stream) o el Woodstox Implementación de StAX (que es significativamente más rápida, en mi experiencia), recomendaría crear un filtro de eventos XML que primero coincida con el nombre del tipo de elemento (para capturar su <txn> elementos). Esto creará pequeñas ráfagas de eventos (elemento, atributo, texto) que se pueden verificar para sus valores de usuario coincidentes. Tras una coincidencia adecuada, puede extraer la información necesaria de los eventos o canalizar los eventos delimitados para construir un mini DOM a partir de ellos si encuentra que el resultado es más fácil de navegar. Pero parece que eso podría ser excesivo si el marcado es simple.

Este sería probablemente el enfoque más simple y rápido posible y evitaría la sobrecarga de memoria de construir un DOM. Si pasó los nombres del elemento y el atributo al filtro (para que su algoritmo de coincidencia sea configurable), podría hacerlo relativamente genérico.

Respondido 03 Abr '13, 14:04

¿Has oído hablar de vtd-xml? - vtd-xml-autor

No hasta tu comentario, no, no lo había hecho. He descargado la distribución y estaré encantado de probarla. Si funciona como se afirma, consideraría usarlo en entornos de producción, pero el único problema que veo me inclina a preguntar (ya que usted es su autor) si estaría dispuesto a lanzar también vtd-xml bajo una LGPL o Apache. ¿licencia? Simplemente no podemos usar GPL en nuestro entorno. Gracias por la propina en cualquier caso. - Ichiro Furusato

@IchiroFurusato - Gran comentario. - pinguino

Stax y xpath son cosas muy diferentes. Stax le permite analizar un documento XML de transmisión solo en una dirección hacia adelante. Xpath permite analizar en ambas direcciones. Stax es un analizador XML de transmisión muy rápida, pero, si desea xpath, Java tiene una biblioteca separada para eso.

Eche un vistazo a esta pregunta para una discusión muy similar: ¿Existe algún procesador XPath para el modelo SAX?

contestado el 23 de mayo de 17 a las 13:05

Si me va a rechazar, deje un comentario. ¡De esa manera todos aprenden! - Jon7

Votar en contra porque su declaración "Stax y xpath son cosas muy diferentes" no es correcta. XPath (al menos el subconjunto de él) aún se puede implementar en el modelo Stax (modelo de extracción). Está implementado en C # msdn.microsoft.com/en-us/library/ms950778.aspx - TriCore

Analizamos regularmente archivos XML complejos de más de 1GB utilizando un analizador SAX que hace exactamente lo que usted describió: extrae árboles DOM parciales que pueden consultarse convenientemente usando XPATH.

Escribí en un blog sobre eso aquí - Está usando un SAX, no un analizador StAX, pero puede valer la pena echarle un vistazo.

Respondido 17 Jul 20, 15:07

Definitivamente es un caso de uso para XProc con una implementación de procesamiento paralelo y transmisión como QuiXProc (http://code.google.com/p/quixproc)

En esta situación, tendrá que usar

  <p:for-each>
    <p:iteration-source select="//transactions/txn"/>
    <!-- you processing on a small file -->
  </p:for-each>

Incluso puede envolver cada una de las transformaciones resultantes con una sola línea de XProc

  <p:wrap-sequence wrapper="transactions"/>

Espero que esto ayude

Respondido el 03 de Septiembre de 11 a las 11:09

Una solución divertida para procesar archivos XML de gran tamaño> 10 GB.

  1. Utilice ANTLR para crear compensaciones de bytes para las partes de interés. Esto ahorrará algo de memoria en comparación con un enfoque basado en DOM.
  2. Utilice Jaxb para leer partes desde la posición del byte

Encuentre detalles en el ejemplo de volcados de wikipedia (17 GB) en esta respuesta SO https://stackoverflow.com/a/43367629/1485527

Respondido 26 Feb 18, 12:02

Respondido 27 ago 11, 21:08

¿Necesita procesarlo rápidamente o necesita búsquedas rápidas en los datos? Estos requisitos necesitan un enfoque diferente.

Para una lectura rápida de todos los datos, StAX estará bien.

Si necesita búsquedas rápidas de lo que podría necesitar cargarlo en alguna base de datos, Berkeley DB XML, por ejemplo

Respondido 27 ago 11, 23:08

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.