java - Acelerando xpath
performance nodes (6)
¿Qué tipo de analizador estás usando?
DOM extrae todo el documento en la memoria: una vez que extrae todo el documento en la memoria, sus operaciones pueden ser rápidas, pero hacerlo en una aplicación web o en un bucle for puede tener un impacto.
El analizador SAX realiza el análisis bajo demanda y carga nodos cuando lo solicite.
Intente utilizar una implementación de analizador que se adapte a sus necesidades.
Tengo un documento de 1000 entradas cuyo formato es algo así como
<Example>
<Entry>
<n1></n1>
<n2></n2>
</Entry>
<Entry>
<n1></n1>
<n2></n2>
</Entry>
<!--and so on-->
Hay más de 1000 nodos de entrada aquí. Estoy escribiendo un programa Java que básicamente obtiene todos los nodos uno por uno y analiza algunos en cada nodo. Pero el problema es que el tiempo de recuperación de los nodos aumenta con su no. Por ejemplo, toma 78 milisegundos para recuperar el primer nodo 100 ms para recuperar el segundo y sigue aumentando. Y para recuperar el nodo 999 lleva más de 5 segundos. Esto es extremadamente lento Estaríamos conectando este código a archivos XML que tienen incluso más de 1000 entradas. Algunos como millones. El tiempo total para analizar el documento completo es de más de 5 minutos.
Estoy usando este código simple para atravesarlo. Aquí nxp
es mi propia clase que tiene todos los métodos para obtener nodos de xpath.
nxp.fromXpathToNode("/Example/Entry" + "[" + i + "]", doc);
y doc
es el documento para el archivo. i
es el no de nodo para recuperar.
También cuando intento algo como esto
List<Node> nl = nxp.fromXpathToNodes("/Example/Entry",doc);
content = nl.get(i);
Me enfrento al mismo problema.
Alguien tiene alguna solución sobre cómo acelerar el tretirival de los nodos, por lo que toma el mismo tiempo para obtener el primer nodo y el nodo 1000 del archivo XML.
Gracias
aquí está el código para xpathtonode.
public Node fromXpathToNode(String expression, Node context)
{
try
{
return (Node)this.getCachedExpression(expression).evaluate(context, XPathConstants.NODE);
}
catch (Exception cause)
{
throw new RuntimeException(cause);
}
}
y aquí está el código para fromxpathtonodes.
public List<Node> fromXpathToNodes(String expression, Node context)
{
List<Node> nodes = new ArrayList<Node>();
NodeList results = null;
try
{
results = (NodeList)this.getCachedExpression(expression).evaluate(context, XPathConstants.NODESET);
for (int index = 0; index < results.getLength(); index++)
{
nodes.add(results.item(index));
}
}
catch (Exception cause)
{
throw new RuntimeException(cause);
}
return nodes;
}
y aquí está el comienzo
clase pública NativeXpathEngine implementa XpathEngine
{
fábrica privada final de XPathFactory;
private final XPath engine;
/**
* Cache for previously compiled XPath expressions. {@link XPathExpression#hashCode()}
* is not reliable or consistent so use the textual representation instead.
*/
private final Map<String, XPathExpression> cachedExpressions;
public NativeXpathEngine()
{
super();
this.factory = XPathFactory.newInstance();
this.engine = factory.newXPath();
this.cachedExpressions = new HashMap<String, XPathExpression>();
}
Si necesita analizar documentos grandes pero planos, SAX es una buena alternativa. Le permite manejar el XML como una secuencia en lugar de generar un DOM enorme. Su ejemplo podría ser analizado usando un ContentHandler como este:
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.ext.DefaultHandler2;
public class ExampleHandler extends DefaultHandler2 {
private StringBuffer chars = new StringBuffer(1000);
private MyEntry currentEntry;
private MyEntryHandler myEntryHandler;
ExampleHandler(MyEntryHandler myEntryHandler) {
this.myEntryHandler = myEntryHandler;
}
@Override
public void characters(char[] ch, int start, int length)
throws SAXException {
chars.append(ch);
}
@Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
if ("Entry".equals(localName)) {
myEntryHandler.handle(currentEntry);
currentEntry = null;
}
else if ("n1".equals(localName)) {
currentEntry.setN1(chars.toString());
}
else if ("n2".equals(localName)) {
currentEntry.setN2(chars.toString());
}
}
@Override
public void startElement(String uri, String localName, String qName,
Attributes atts) throws SAXException {
chars.setLength(0);
if ("Entry".equals(localName)) {
currentEntry = new MyEntry();
}
}
}
Si el documento tiene una estructura más profunda y compleja, necesitará usar Stacks para realizar un seguimiento de la ruta actual en el documento. Entonces debería considerar escribir un ContentHandler de propósito general para hacer el trabajo sucio y usarlo con sus manejadores dependientes del tipo de documento.
Utilice la biblioteca JAXEN para xpaths: http://jaxen.codehaus.org/
Pruebe VTD-XML . Utiliza menos memoria que DOM. Es más fácil de usar que SAX y es compatible con XPath. Aquí hay un código de muestra para ayudarlo a comenzar. Aplica una XPath para obtener los elementos de entrada y luego imprime los elementos secundarios n1 y n2.
final VTDGen vg = new VTDGen();
vg.parseFile("/path/to/file.xml", false);
final VTDNav vn = vg.getNav();
final AutoPilot ap = new AutoPilot(vn);
ap.selectXPath("/Example/Entry");
int count = 1;
while (ap.evalXPath() != -1) {
System.out.println("Inside Entry: " + count);
//move to n1 child
vn.toElement(VTDNav.FIRST_CHILD, "n1");
System.out.println("/tn1: " + vn.toNormalizedString(vn.getText()));
//move to n2 child
vn.toElement(VTDNav.NEXT_SIBLING, "n2");
System.out.println("/tn2: " + vn.toNormalizedString(vn.getText()));
//move back to parent
vn.toElement(VTDNav.PARENT);
count++;
}
Tuve un problema similar con la evaluación Xpath, intenté usar CachedXPathAPI, que es más rápido en 100 veces que XPathApi que se utilizó anteriormente. se proporciona más información sobre este API aquí: http://xml.apache.org/xalan-j/apidocs/org/apache/xpath/CachedXPathAPI.html
Espero eso ayude. Saludos, Madhusudhan
La solución correcta es separar el nodo justo después de llamar al elemento (i), de esta manera:
Node node = results.item(index)
node.getParentNode().removeChild(node)
nodes.add(node)
Ver XPath. El rendimiento de evaluación se ralentiza (absurdamente) a través de múltiples llamadas.