Author: vgritsenko Date: Sun Nov 9 13:55:21 2008 New Revision: 712568 URL: http://svn.apache.org/viewvc?rev=712568&view=rev Log: optimize xpath query performance. tweak indexed search test - does not run reliably in xmlrpc integration tests mode due to network overhead.
Modified: xml/xindice/trunk/java/src/org/apache/xindice/core/query/XPathQueryResolver.java xml/xindice/trunk/java/src/org/apache/xindice/core/xupdate/XPathQueryImpl.java xml/xindice/trunk/java/tests/src/org/apache/xindice/integration/client/services/IndexedSearchTest.java Modified: xml/xindice/trunk/java/src/org/apache/xindice/core/query/XPathQueryResolver.java URL: http://svn.apache.org/viewvc/xml/xindice/trunk/java/src/org/apache/xindice/core/query/XPathQueryResolver.java?rev=712568&r1=712567&r2=712568&view=diff ============================================================================== --- xml/xindice/trunk/java/src/org/apache/xindice/core/query/XPathQueryResolver.java (original) +++ xml/xindice/trunk/java/src/org/apache/xindice/core/query/XPathQueryResolver.java Sun Nov 9 13:55:21 2008 @@ -102,8 +102,6 @@ private static final Log log = LogFactory.getLog(XPathQueryResolver.class); - private static final Key[] EMPTY_KEYS = new Key[0]; - private static final Key[][] EMPTY_KEYSET = new Key[0][0]; private static final String WILDCARD = "*"; public static final String STYLE_XPATH = "XPath"; @@ -335,7 +333,7 @@ while (rs.hasMoreRecords()) { set.add(rs.getNextKey()); } - keySet = (Key[]) set.toArray(EMPTY_KEYS); + keySet = (Key[]) set.toArray(new Key[set.size()]); } return new ResultSet(context, pr, keySet, query, parameters); @@ -348,15 +346,16 @@ } private Key[] andKeys(List list) { - if (!list.isEmpty()) { - if (list.size() > 1) { - Key[][] keys = (Key[][]) list.toArray(EMPTY_KEYSET); - return QueryEngine.andKeySets(keys); - } else - return (Key[]) list.get(0); - } else { + if (list.isEmpty()) { return null; } + + if (list.size() > 1) { + Key[][] keys = (Key[][]) list.toArray(new Key[list.size()][]); + return QueryEngine.andKeySets(keys); + } + + return (Key[]) list.get(0); } // Evaluation Methods @@ -1121,7 +1120,9 @@ Indexer idx = context.getIndexManager().getBestIndexer(Indexer.STYLE_NODEVALUE, pattern); if (idx != null) { return new NamedKeys(nk.name, nk.attribute, QueryEngine.getUniqueKeys(idx.queryMatches(iq))); - } else if (autoIndex) { + } + + if (autoIndex) { // TODO: This has to *not* be hardcoded Element e = new DocumentImpl().createElement("index"); e.setAttribute("class", "org.apache.xindice.core.indexer.ValueIndexer"); @@ -1284,9 +1285,8 @@ /** * NamedKeys */ - - private class NamedKeys { - public boolean attribute = false; + private static class NamedKeys { + public boolean attribute; public NodePath name; public Key[] keys; @@ -1297,21 +1297,40 @@ } } + private static final ErrorListener XPATH_ERROR_LISTENER = new ErrorListener() { + public void fatalError(TransformerException te) { + if (log.isFatalEnabled()) { + log.fatal("No message", te); + } + } + + public void error(TransformerException te) { + if (log.isErrorEnabled()) { + log.error("No message", te); + } + } + + public void warning(TransformerException te) { + if (log.isWarnEnabled()) { + log.warn("No message", te); + } + } + }; + /** * ResultSet */ - private class ResultSet implements NodeSet { - public Collection context; - public String query; - public ErrorListener errors; - public PrefixResolver pr; - public XPath xp; - - public Key[] keySet; - public int keyPos = 0; - public NodeIterator ni; - public Object node; + private Collection context; + private String query; + private PrefixResolver pr; + private XPathResolverContext xpc; + private XPath xp; + + private Key[] keySet; + private int keyPos = 0; + private NodeIterator ni; + private Object node; private Map parameters; public ResultSet(Collection context, PrefixResolver pr, Key[] keySet, String query, Map parameters) { @@ -1321,26 +1340,6 @@ this.query = query; this.parameters = parameters; - errors = new ErrorListener() { - public void fatalError(TransformerException te) { - if (log.isFatalEnabled()) { - log.fatal("No message", te); - } - } - - public void error(TransformerException te) { - if (log.isErrorEnabled()) { - log.error("No message", te); - } - } - - public void warning(TransformerException te) { - if (log.isWarnEnabled()) { - log.warn("No message", te); - } - } - }; - try { prepareNextNode(); } catch (Exception e) { @@ -1352,10 +1351,10 @@ try { if (XCOMPILER3) { return (XPath) XPATH.newInstance( - new Object[] {query, null, pfx, new Integer(XPath.SELECT), errors, functionTable}); + new Object[] {query, null, pfx, new Integer(XPath.SELECT), XPATH_ERROR_LISTENER, functionTable}); } else { return (XPath) XPATH.newInstance( - new Object[] {query, null, pfx, new Integer(XPath.SELECT), errors}); + new Object[] {query, null, pfx, new Integer(XPath.SELECT), XPATH_ERROR_LISTENER}); } } catch (Exception e) { throw new RuntimeException("Could not instantiate Compiler: " + e); @@ -1383,7 +1382,10 @@ continue; } - XPathResolverContext xpc = new XPathResolverContext(parameters); + if (xpc == null) { + xpc = new XPathResolverContext(parameters); + } + PrefixResolver pfx; if (pr == null) { pfx = new PrefixResolverDefault(d.getDocumentElement()); @@ -1463,52 +1465,30 @@ /* This only implements what we need internally */ private static class EmptyNodeIterator implements NodeIterator { - - /* (non-Javadoc) - * @see org.w3c.dom.traversal.NodeIterator#getWhatToShow() - */ public int getWhatToShow() { throw new UnsupportedOperationException(); } - /* (non-Javadoc) - * @see org.w3c.dom.traversal.NodeIterator#detach() - */ public void detach() { throw new UnsupportedOperationException(); } - /* (non-Javadoc) - * @see org.w3c.dom.traversal.NodeIterator#getExpandEntityReferences() - */ public boolean getExpandEntityReferences() { throw new UnsupportedOperationException(); } - /* (non-Javadoc) - * @see org.w3c.dom.traversal.NodeIterator#getRoot() - */ public Node getRoot() { throw new UnsupportedOperationException(); } - /* (non-Javadoc) - * @see org.w3c.dom.traversal.NodeIterator#nextNode() - */ public Node nextNode() throws DOMException { return null; } - /* (non-Javadoc) - * @see org.w3c.dom.traversal.NodeIterator#previousNode() - */ public Node previousNode() throws DOMException { throw new UnsupportedOperationException(); } - /* (non-Javadoc) - * @see org.w3c.dom.traversal.NodeIterator#getFilter() - */ public NodeFilter getFilter() { throw new UnsupportedOperationException(); } @@ -1538,8 +1518,8 @@ /** * Helper class to track path to a node in the XPath expression */ - private class NodePath { - private boolean absolute = false; + private static class NodePath { + private boolean absolute; private LinkedList path = new LinkedList(); private String attr; Modified: xml/xindice/trunk/java/src/org/apache/xindice/core/xupdate/XPathQueryImpl.java URL: http://svn.apache.org/viewvc/xml/xindice/trunk/java/src/org/apache/xindice/core/xupdate/XPathQueryImpl.java?rev=712568&r1=712567&r2=712568&view=diff ============================================================================== --- xml/xindice/trunk/java/src/org/apache/xindice/core/xupdate/XPathQueryImpl.java (original) +++ xml/xindice/trunk/java/src/org/apache/xindice/core/xupdate/XPathQueryImpl.java Sun Nov 9 13:55:21 2008 @@ -37,9 +37,8 @@ */ public final class XPathQueryImpl implements XPathQuery { private String qstring; - private Node rootNode; private Node namespace; - private NodeFilter filter; + private XPathContext xpc; private XPath xpath; /** @@ -50,6 +49,7 @@ */ public void setQString(String qstring) throws Exception { this.qstring = qstring; + this.xpath = null; } /** @@ -60,6 +60,7 @@ */ public void setNamespace(Node namespace) throws Exception { this.namespace = namespace; + this.xpath = null; } /** @@ -69,7 +70,7 @@ * @exception Exception Description of Exception */ public void setNodeFilter(NodeFilter filter) throws Exception { - this.filter = filter; + // this.filter = filter; } /** @@ -84,28 +85,31 @@ rootNode = ((Document) rootNode).getDocumentElement(); } - this.rootNode = rootNode; - // Since we don't have a XML Parser involved here, install some default // support for things like namespaces, etc. - XPathContext xpathSupport = new XPathContext(); + if (xpc == null) { + xpc = new XPathContext(); + } - PrefixResolver prefixResolver = null; // Create an object to resolve namespace prefixes. + PrefixResolver pfx; if (namespace != null) { if (namespace.getNodeType() == Node.DOCUMENT_NODE) { namespace = ((Document) namespace).getDocumentElement(); } - prefixResolver = new PrefixResolverDefault(namespace); + pfx = new PrefixResolverDefault(namespace); } else { - prefixResolver = new PrefixResolverDefault(rootNode); + pfx = new PrefixResolverDefault(rootNode); + xpath = null; } // Create the XPath object. - xpath = new XPath(qstring, null, prefixResolver, XPath.SELECT, null); + if (xpath == null) { + xpath = new XPath(qstring, null, pfx, XPath.SELECT, null); + } // execute the XPath query on the specified root node - return new XObjectImpl(xpath.execute(xpathSupport, rootNode, prefixResolver)); + return new XObjectImpl(xpath.execute(xpc, rootNode, pfx)); } } Modified: xml/xindice/trunk/java/tests/src/org/apache/xindice/integration/client/services/IndexedSearchTest.java URL: http://svn.apache.org/viewvc/xml/xindice/trunk/java/tests/src/org/apache/xindice/integration/client/services/IndexedSearchTest.java?rev=712568&r1=712567&r2=712568&view=diff ============================================================================== --- xml/xindice/trunk/java/tests/src/org/apache/xindice/integration/client/services/IndexedSearchTest.java (original) +++ xml/xindice/trunk/java/tests/src/org/apache/xindice/integration/client/services/IndexedSearchTest.java Sun Nov 9 13:55:21 2008 @@ -19,8 +19,6 @@ package org.apache.xindice.integration.client.services; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; import org.apache.xindice.integration.client.AbstractXmlDbClientTest; import org.apache.xindice.integration.client.XmlDbClientSetup; import org.apache.xindice.xml.NodeSource; @@ -51,8 +49,6 @@ */ public class IndexedSearchTest extends AbstractXmlDbClientTest { - private static final Log itsLog = LogFactory.getLog(IndexedSearchTest.class); - /** * path of collection we use (and reuse to avoid document insertion overhead for each test case) */ @@ -119,7 +115,7 @@ public Result(ResourceSet theResourceSet, long theElapsedTime) { itsResourceSet = theResourceSet; - itsElapsedTime = theElapsedTime; + itsElapsedTime = theElapsedTime > 0 ? theElapsedTime : 1; } /** @@ -150,8 +146,8 @@ private long itsExpectedResourceCount; private Object[] itsExpectedResources; private int itsIndexSpeedupFactor; - private boolean itsIndexCreated = false; - private boolean itsTestDocumentsAdded = false; + private boolean itsIndexCreated; + private boolean itsTestDocumentsAdded; /** * Creates a new test definition. @@ -197,14 +193,15 @@ Result aResult = runNonIndexed(); checkResult(aResult); long aNonIndexedTime = aResult.getElapsedTime(); + aResult = runIndexed(); checkResult(aResult); long anIndexedTime = aResult.getElapsedTime(); - itsLog.info(itsDescription + - ": Non-indexed time = " + aNonIndexedTime + - " Indexed time = " + anIndexedTime + - " Index speedup:" + (anIndexedTime > 0 ? " " + aNonIndexedTime / anIndexedTime + "X" : - anIndexedTime == 0 ? " >" + aNonIndexedTime + "X" : " (Indexed query not run)")); + + long speedUp = aNonIndexedTime / anIndexedTime; + System.out.println(itsDescription + ": Non-indexed: " + aNonIndexedTime + "ms, " + + "Indexed: " + anIndexedTime + "ms, " + + "Speedup: " + speedUp + "x"); if (anIndexedTime * itsIndexSpeedupFactor > aNonIndexedTime) { fail("Query apparently did not use index" + " Non-indexed time = " + aNonIndexedTime + " Indexed time = " + anIndexedTime); @@ -245,11 +242,17 @@ */ public Result runQuery() throws Exception { Collection col = IndexedSearchTest.this.client.getCollection(IndexedSearchTest.COLLECTION_PATH); - XPathQueryService xpathservice = (XPathQueryService) col.getService("XPathQueryService", "1.0"); + XPathQueryService service = (XPathQueryService) col.getService("XPathQueryService", "1.0"); + + // Warm Up + service.query(itsTestQuery); - org.apache.xindice.Stopwatch aStopwatch = new org.apache.xindice.Stopwatch("Non-indexed starts-with query", true); - ResourceSet resultSet = xpathservice.query(itsTestQuery); + org.apache.xindice.Stopwatch aStopwatch = new org.apache.xindice.Stopwatch(null, true); + // Run twice since indexed query takes too little time + service.query(itsTestQuery); + ResourceSet resultSet = service.query(itsTestQuery); aStopwatch.stop(); + return new Result(resultSet, aStopwatch.elapsed()); } @@ -274,15 +277,8 @@ Node aNode = aResource.getContentAsDOM(); int anExpectedSourceDocumentIndex = ((Integer) itsExpectedResources[anIndex * 2]).intValue(); String anExpected = "<?xml version=\"1.0\"?>\n" + addSource((String) itsExpectedResources[anIndex * 2 + 1], - TEST_DOCUMENT_PREFIX + anExpectedSourceDocumentIndex, - IndexedSearchTest.COLLECTION_PATH); + TEST_DOCUMENT_PREFIX + anExpectedSourceDocumentIndex); String anActual = TextWriter.toString(aNode); - //itsLog.info(itsDescription); - //itsLog.info("Expected resource " + (anIndex / 2) + ":"); - //itsLog.info("Expected:"); - //itsLog.info(anExpected); - //itsLog.info("Actual:"); - //itsLog.info(anActual); XMLAssert.assertXMLEqual("While checking target Resource " + anIndex, anExpected, anActual); } @@ -295,9 +291,8 @@ * * @param theXML XML to add source to * @param theKey document key to add - * @param theCollectionName source collection to add */ - public String addSource(String theXML, String theKey, String theCollectionName) throws Exception { + public String addSource(String theXML, String theKey) throws Exception { DocumentBuilder aBuilder = itsDocumentBuilderFactory.newDocumentBuilder(); Document aDocument = aBuilder.parse( new InputSource(new StringReader(theXML))); @@ -305,8 +300,7 @@ final String pfx = "src"; elm.setAttribute(NodeImpl.XMLNS_PREFIX + ":" + pfx, NodeSource.SOURCE_NS); - elm.setAttribute(pfx + ":" + NodeSource.SOURCE_COL, - "/" + COLLECTION_PATH); + elm.setAttribute(pfx + ":" + NodeSource.SOURCE_COL, "/" + COLLECTION_PATH); elm.setAttribute(pfx + ":" + NodeSource.SOURCE_KEY, theKey); return TextWriter.toString(elm); } @@ -389,7 +383,7 @@ "SENA", // index name "Name", // index type "address", // index pattern - 8, // indexed query speedup expected (conservative) + 5, // indexed query speedup expected (conservative) new String[] { // test docs specifically for this test "<?xml version='1.0'?>" + "<person number3='yes'>" + @@ -446,7 +440,7 @@ "SENA", // index name "Name", // index type "second", // index pattern - 10, // indexed query speedup expected (conservative) + 6, // indexed query speedup expected (conservative) new String[] { // test docs specifically for this test "<?xml version='1.0'?>" + "<person number3='yes'>" + @@ -483,7 +477,7 @@ "SESA", // index name "Name", // index type "[EMAIL PROTECTED]", // index pattern - 8, // indexed query speedup expected (conservative) + 9, // indexed query speedup expected (conservative) new String[] { // test docs specifically for this test "<?xml version='1.0'?>" + "<person number3='yes'>" + @@ -519,7 +513,7 @@ "SEWA", // index name "Name", // index type "[EMAIL PROTECTED]", // index pattern - 6, // indexed query speedup expected (conservative) + 7, // indexed query speedup expected (conservative) new String[] { // test docs specifically for this test "<?xml version='1.0'?>" + "<person number3='yes'>" + @@ -666,7 +660,7 @@ "SENA", // index name "Value", // index type "last", // index pattern - 8, // indexed query speedup expected (conservative) + 6, // indexed query speedup expected (conservative) new String[] { // test docs specifically for this test "<?xml version='1.0'?>" + "<person number3='yes'>" + @@ -768,7 +762,7 @@ "SESA", // index name "Value", // index type "[EMAIL PROTECTED]", // index pattern - 6, // indexed query speedup expected (conservative) + 9, // indexed query speedup expected (conservative) new String[] { // test docs specifically for this test "<?xml version='1.0'?>" + "<person number3='yes'>" + @@ -802,7 +796,7 @@ "SENA", // index name "Value", // index type "[EMAIL PROTECTED]", // index pattern - 6, // indexed query speedup expected (conservative) + 9, // indexed query speedup expected (conservative) new String[] { // test docs specifically for this test "<?xml version='1.0'?>" + "<person number3='yes'>" + @@ -948,7 +942,7 @@ "SESA", // index name "Value", // index type "/person/[EMAIL PROTECTED]", // index pattern - 6, // indexed query speedup expected (conservative) + 9, // indexed query speedup expected (conservative) new String[] { // test docs specifically for this test "<?xml version='1.0'?>" + "<person number3='yes'>" +