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 2016/11/01 09:30:15 UTC
svn commit: r1767458 - in /jackrabbit/oak/trunk/oak-core/src:
main/java/org/apache/jackrabbit/oak/query/
main/java/org/apache/jackrabbit/oak/query/ast/
test/java/org/apache/jackrabbit/oak/query/
Author: thomasm
Date: Tue Nov 1 09:30:15 2016
New Revision: 1767458
URL: http://svn.apache.org/viewvc?rev=1767458&view=rev
Log:
OAK-4681 Automatically convert *all* "or" queries to "union" for SQL-2
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryEngineSettings.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/AndImpl.java
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/SQL2OptimiseQueryTest.java
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryEngineSettings.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryEngineSettings.java?rev=1767458&r1=1767457&r2=1767458&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryEngineSettings.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryEngineSettings.java Tue Nov 1 09:30:15 2016
@@ -31,6 +31,11 @@ public class QueryEngineSettings impleme
*/
public static final String SQL2_OPTIMISATION_FLAG = "oak.query.sql2optimisation";
+ public static final String SQL2_OPTIMISATION_FLAG_2 = "oak.query.sql2optimisation2";
+
+ public static final boolean SQL2_OPTIMIZATION_2 =
+ Boolean.parseBoolean(System.getProperty(SQL2_OPTIMISATION_FLAG_2, "true"));
+
private static final int DEFAULT_QUERY_LIMIT_IN_MEMORY =
Integer.getInteger("oak.queryLimitInMemory", Integer.MAX_VALUE);
@@ -52,8 +57,9 @@ public class QueryEngineSettings impleme
private boolean fullTextComparisonWithoutIndex =
DEFAULT_FULL_TEXT_COMPARISON_WITHOUT_INDEX;
- private boolean sql2Optimisation = Boolean.parseBoolean(System.getProperty(SQL2_OPTIMISATION_FLAG, "true"));
-
+ private boolean sql2Optimisation =
+ Boolean.parseBoolean(System.getProperty(SQL2_OPTIMISATION_FLAG, "true"));
+
public QueryEngineSettings() {
}
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/AndImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/AndImpl.java?rev=1767458&r1=1767457&r2=1767458&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/AndImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/AndImpl.java Tue Nov 1 09:30:15 2016
@@ -26,10 +26,12 @@ import static org.apache.jackrabbit.oak.
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
+import org.apache.jackrabbit.oak.query.QueryEngineSettings;
import org.apache.jackrabbit.oak.query.fulltext.FullTextAnd;
import org.apache.jackrabbit.oak.query.fulltext.FullTextExpression;
import org.apache.jackrabbit.oak.query.index.FilterImpl;
@@ -217,11 +219,61 @@ public class AndImpl extends ConstraintI
}
return new AndImpl(clone);
}
+
+ public void addToUnionList(Set<ConstraintImpl> target) {
+ // conditions of type
+ // @a = 1 and (@x = 1 or @y = 2)
+ // are automatically converted to
+ // (@a = 1 and @x = 1) union (@a = 1 and @y = 2)
+ AndImpl and = pullOrRight();
+ ConstraintImpl last = and.getLastConstraint();
+ if (last instanceof OrImpl) {
+ OrImpl or = (OrImpl) last;
+ // same as above, but with the added "and"
+ for(ConstraintImpl c : or.getConstraints()) {
+ ArrayList<ConstraintImpl> list = and.getFirstConstraints();
+ list.add(c);
+ new AndImpl(list).addToUnionList(target);
+ }
+ return;
+ }
+ target.add(this);
+ }
+
+ private ArrayList<ConstraintImpl> getFirstConstraints() {
+ ArrayList<ConstraintImpl> list = new ArrayList<ConstraintImpl>(constraints.size() - 1);
+ list.addAll(constraints.subList(0, constraints.size() - 1));
+ return list;
+ }
+
+ private ConstraintImpl getLastConstraint() {
+ return constraints.get(constraints.size() - 1);
+ }
+
+ public AndImpl pullOrRight() {
+ if (getLastConstraint() instanceof OrImpl) {
+ return this;
+ }
+ for (int i = 0; i < constraints.size() - 1; i++) {
+ ConstraintImpl c = constraints.get(i);
+ if (c instanceof OrImpl) {
+ ArrayList<ConstraintImpl> list = new ArrayList<ConstraintImpl>();
+ list.addAll(constraints);
+ list.remove(i);
+ list.add(c);
+ return new AndImpl(list);
+ }
+ }
+ return this;
+ }
@Override
public Set<ConstraintImpl> convertToUnion() {
- Set<ConstraintImpl> union = Sets.newHashSet();
- Set<ConstraintImpl> result = Sets.newHashSet();
+ // use linked hash sets where needed, so that the order of queries
+ // within the UNION is always the same (independent of the JVM
+ // implementation)
+ Set<ConstraintImpl> union = Sets.newLinkedHashSet();
+ Set<ConstraintImpl> result = Sets.newLinkedHashSet();
Set<ConstraintImpl> nonUnion = Sets.newHashSet();
for (ConstraintImpl c : constraints) {
@@ -240,11 +292,19 @@ public class AndImpl extends ConstraintI
result.add(new AndImpl(c, right));
}
} else {
- // in this case prefer to be conservative and don't optimize. This could happen when for
+ // This could happen when for
// example: WHERE (a OR b) AND (c OR d).
- // This should be translated into a AND c, a AND d, b AND c, b AND d.
+ // This can be translated into a AND c, a AND d, b AND c, b AND d.
+ if (QueryEngineSettings.SQL2_OPTIMIZATION_2) {
+ Set<ConstraintImpl> set = Sets.newLinkedHashSet();
+ addToUnionList(set);
+ if (set.size() == 1) {
+ // not a union: same condition as before
+ return Collections.emptySet();
+ }
+ return set;
+ }
}
-
return result;
}
Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/SQL2OptimiseQueryTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/SQL2OptimiseQueryTest.java?rev=1767458&r1=1767457&r2=1767458&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/SQL2OptimiseQueryTest.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/SQL2OptimiseQueryTest.java Tue Nov 1 09:30:15 2016
@@ -27,6 +27,7 @@ import static org.apache.jackrabbit.oak.
import static org.apache.jackrabbit.oak.query.QueryEngineImpl.QuerySelectionMode.CHEAPEST;
import static org.apache.jackrabbit.oak.query.QueryEngineImpl.QuerySelectionMode.ORIGINAL;
import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertThat;
@@ -226,6 +227,45 @@ public class SQL2OptimiseQueryTest exten
assertNotSame(original, optimised);
}
+ /**
+ * ensure that an optimisation is available for the provided queries.
+ *
+ * @throws ParseException
+ */
+ @Test
+ public void optimiseAndOrAnd() throws ParseException {
+ optimiseAndOrAnd(
+ "select * from [nt:unstructured] as [c] " +
+ "where ([a]=1 or [b]=2) and ([x]=3 or [y]=4)",
+ "(y = 4) and (b = 2), " +
+ "(y = 4) and (a = 1), " +
+ "(x = 3) and (b = 2), " +
+ "(x = 3) and (a = 1)");
+ optimiseAndOrAnd(
+ "select * from [nt:unstructured] as [c] " +
+ "where ([a]=1 or [b]=2 or ([c]=3 and [d]=4)) and ([x]=5 or [y]=6)",
+ "(y = 6) and ((c = 3) and (d = 4)), " +
+ "(y = 6) and (b = 2), " +
+ "(y = 6) and (a = 1), " +
+ "(x = 5) and ((c = 3) and (d = 4)), " +
+ "(x = 5) and (b = 2), " +
+ "(x = 5) and (a = 1)");
+ }
+
+ private void optimiseAndOrAnd(String statement, String expected) throws ParseException {
+ SQL2Parser parser = new SQL2Parser(getMappings(), getNodeTypes(), qeSettings);
+ Query original;
+ original = parser.parse(statement, false);
+ assertNotNull(original);
+ String optimized = original.buildAlternativeQuery().toString();
+ optimized = optimized.replaceAll("\\[", "").replaceAll("\\]","");
+ optimized = optimized.replaceAll("select c.jcr:primaryType as c.jcr:primaryType ", "");
+ optimized = optimized.replaceAll("from nt:unstructured as c where ", "");
+ optimized = optimized.replaceAll("c\\.", "");
+ optimized = optimized.replaceAll(" union ", ", ");
+ assertEquals(expected, optimized);
+ }
+
private NamePathMapper getMappings() {
return new NamePathMapperImpl(
new LocalNameMapper(root, QueryEngine.NO_MAPPINGS));