You are viewing a plain text version of this content. The canonical link for it is here.
Posted to oak-commits@jackrabbit.apache.org by th...@apache.org on 2015/05/22 12:11:58 UTC

svn commit: r1681064 - in /jackrabbit/oak/branches/1.0/oak-core/src: main/java/org/apache/jackrabbit/oak/query/xpath/ test/java/org/apache/jackrabbit/oak/query/

Author: thomasm
Date: Fri May 22 10:11:57 2015
New Revision: 1681064

URL: http://svn.apache.org/r1681064
Log:
OAK-2873 Performance problems with many "or" conditions

Modified:
    jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/query/xpath/Expression.java
    jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/query/xpath/XPathToSQL2Converter.java
    jackrabbit/oak/branches/1.0/oak-core/src/test/java/org/apache/jackrabbit/oak/query/LargeQueryTest.java

Modified: jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/query/xpath/Expression.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/query/xpath/Expression.java?rev=1681064&r1=1681063&r2=1681064&view=diff
==============================================================================
--- jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/query/xpath/Expression.java (original)
+++ jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/query/xpath/Expression.java Fri May 22 10:11:57 2015
@@ -318,12 +318,30 @@ abstract class Expression {
             }
             String commonLeft = getCommonLeftPart();
             if (commonLeft == null) {
+                // the case:
+                // (other>0 or x=1) or x=2
+                // can be converted to:
+                // other>0 or (x=1 or x=2)
+                // which can then be optimized
+                if (left instanceof OrCondition) {
+                    OrCondition orLeft = (OrCondition) left;
+                    Expression l1 = orLeft.left;
+                    Expression l2 = orLeft.right;
+                    OrCondition orRight = new OrCondition(l2, right);
+                    Expression o2 = orRight.optimize();
+                    if (o2 != orRight) {
+                        return new OrCondition(l1, o2);
+                    }
+                }
                 return this;
             }
             // "@x = 1 or @x = 2" is converted to "@x in (1, 2)"
             if (left instanceof InCondition) {
                 InCondition in = (InCondition) left;
                 in.list.addAll(right.getRight());
+                // return a new instance, because we changed
+                // the list
+                in = new InCondition(in.getLeft(), in.list);
                 return in;
             }
             ArrayList<Expression> list = new ArrayList<Expression>();
@@ -676,6 +694,8 @@ abstract class Expression {
     
         final Selector selector;
         final String name;
+        private String cacheString;
+        private boolean cacheOnlySelector;
         
         /**
          * If there was no "@" character in front of the property name. If that
@@ -692,6 +712,11 @@ abstract class Expression {
     
         @Override
         public String toString() {
+            if (cacheString != null) {
+                if (cacheOnlySelector == selector.onlySelector) {
+                    return cacheString;
+                }
+            }
             StringBuilder buff = new StringBuilder();
             if (!selector.onlySelector) {
                 buff.append(selector.name).append('.');
@@ -701,7 +726,9 @@ abstract class Expression {
             } else {
                 buff.append('[').append(name).append(']');
             }
-            return buff.toString();
+            cacheString = buff.toString();
+            cacheOnlySelector = selector.onlySelector;
+            return cacheString;
         }
         
         @Override

Modified: jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/query/xpath/XPathToSQL2Converter.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/query/xpath/XPathToSQL2Converter.java?rev=1681064&r1=1681063&r2=1681064&view=diff
==============================================================================
--- jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/query/xpath/XPathToSQL2Converter.java (original)
+++ jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/query/xpath/XPathToSQL2Converter.java Fri May 22 10:11:57 2015
@@ -432,7 +432,7 @@ public class XPathToSQL2Converter {
         while (readIf("and")) {
             a = new Expression.AndCondition(a, parseCondition());
         }
-        return a;
+        return a.optimize();
     }
 
     private Expression parseCondition() throws ParseException {
@@ -461,7 +461,7 @@ public class XPathToSQL2Converter {
             }
             a = parseCondition(e);
         }
-        return a;
+        return a.optimize();
     }
 
     private Expression.Condition parseCondition(Expression left) throws ParseException {

Modified: jackrabbit/oak/branches/1.0/oak-core/src/test/java/org/apache/jackrabbit/oak/query/LargeQueryTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.0/oak-core/src/test/java/org/apache/jackrabbit/oak/query/LargeQueryTest.java?rev=1681064&r1=1681063&r2=1681064&view=diff
==============================================================================
--- jackrabbit/oak/branches/1.0/oak-core/src/test/java/org/apache/jackrabbit/oak/query/LargeQueryTest.java (original)
+++ jackrabbit/oak/branches/1.0/oak-core/src/test/java/org/apache/jackrabbit/oak/query/LargeQueryTest.java Fri May 22 10:11:57 2015
@@ -26,7 +26,7 @@ import org.junit.Test;
 public class LargeQueryTest {
 
     @Test
-    public void test() throws ParseException {
+    public void testSimpleOr() throws ParseException {
         StringBuilder buff = new StringBuilder("//*[");
         StringBuilder buff2 = new StringBuilder(
                 "select [jcr:path], [jcr:score], * from [nt:base] as a where [x] in(");
@@ -46,4 +46,41 @@ public class LargeQueryTest {
         buff2.append(" /* xpath: ").append(xpath).append(" */");
         assertEquals(buff2.toString(), sql2);
     }
+    
+    @Test
+    public void testCombinedOr() throws ParseException {
+        StringBuilder buff = new StringBuilder("//*[");
+        StringBuilder buff2 = new StringBuilder(
+                "select [jcr:path], [jcr:score], * from [nt:base] as a where [x] in(");
+        int step = 111;
+        for (int i = 0; i < 5000; i++) {
+            if (i % step == 2) {
+                if (i > 0) {
+                    buff.append(" or ");
+                }
+                buff.append("@x>").append(i);
+                buff2.append(") union select [jcr:path], [jcr:score], * from [nt:base] as a " + 
+                        "where [x] > ").append(i);
+                buff2.append(" union select [jcr:path], [jcr:score], * from [nt:base] as a " + 
+                        "where [x] in(");
+            } else {
+                if (i > 0) {
+                    buff.append(" or ");
+                }
+                buff.append("@x=").append(i);
+                if (i > 0 && i % step != 3) {
+                    buff2.append(", ");
+                }
+                buff2.append(i);
+            }
+        }
+        buff.append("]");
+        buff2.append(")");
+        String xpath = buff.toString();
+        XPathToSQL2Converter conv = new XPathToSQL2Converter();
+        String sql2 = conv.convert(xpath);
+        buff2.append(" /* xpath: ").append(xpath).append(" */");
+        assertEquals(buff2.toString(), sql2);
+    }
+    
 }