Author: thomasm
Date: Fri Jun 10 12:49:32 2016
New Revision: 1747703
URL: http://svn.apache.org/viewvc?rev=1747703&view=rev
Log:
OAK-3574 Query engine: support p=lowercase(x) and other function-based indexes
(WIP)
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/DynamicOperandImpl.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/FullTextSearchScoreImpl.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/LengthImpl.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/LowerCaseImpl.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/NativeFunctionImpl.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/NodeLocalNameImpl.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/NodeNameImpl.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/PropertyValueImpl.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/UpperCaseImpl.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/query/QueryConstants.java
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/FilterTest.java
jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/IndexPlanner.java
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/DynamicOperandImpl.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/DynamicOperandImpl.java?rev=1747703&r1=1747702&r2=1747703&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/DynamicOperandImpl.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/DynamicOperandImpl.java
Fri Jun 10 12:49:32 2016
@@ -29,9 +29,33 @@ public abstract class DynamicOperandImpl
public abstract PropertyValue currentProperty();
+ /**
+ * Apply a restriction of type "this = value" to the given filter.
+ *
+ * @param f the filter where the restriction is applied.
+ * @param operator the operator (for example "=").
+ * @param v the value
+ */
public abstract void restrict(FilterImpl f, Operator operator,
PropertyValue v);
-
+
+ /**
+ * Apply a restriction of type "this in (list)" to the given filter.
+ *
+ * @param f the filter where the restriction is applied.
+ * @param list the list of values
+ */
public abstract void restrictList(FilterImpl f, List<PropertyValue> list);
+
+ /**
+ * Apply a restriction of type "function(this) = value" to the given
filter.
+ *
+ * @param functionName the function name (for example "upper")
+ * @param f the filter where the restriction is applied.
+ * @param operator the operator (for example "=").
+ * @param v the value
+ */
+ public abstract void restrictFunction(FilterImpl f, String functionName,
Operator operator,
+ PropertyValue v);
/**
* Check whether the condition can be applied to a selector (to restrict
the
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/FullTextSearchScoreImpl.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/FullTextSearchScoreImpl.java?rev=1747703&r1=1747702&r2=1747703&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/FullTextSearchScoreImpl.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/FullTextSearchScoreImpl.java
Fri Jun 10 12:49:32 2016
@@ -92,6 +92,11 @@ public class FullTextSearchScoreImpl ext
}
@Override
+ public void restrictFunction(FilterImpl f, String functionName, Operator
operator, PropertyValue v) {
+ // optimizations of the type "upper(jcr:score()) = '1'" are not
supported
+ }
+
+ @Override
public boolean canRestrictSelector(SelectorImpl s) {
return s.equals(selector);
}
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/LengthImpl.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/LengthImpl.java?rev=1747703&r1=1747702&r2=1747703&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/LengthImpl.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/LengthImpl.java
Fri Jun 10 12:49:32 2016
@@ -100,6 +100,7 @@ public class LengthImpl extends DynamicO
}
// LENGTH(x) implies x is not null
propertyValue.restrict(f, Operator.NOT_EQUAL, null);
+ propertyValue.restrictFunction(f, "length", operator, v);
}
@Override
@@ -108,6 +109,11 @@ public class LengthImpl extends DynamicO
}
@Override
+ public void restrictFunction(FilterImpl f, String functionName, Operator
operator, PropertyValue v) {
+ // optimizations of the type "upper(length(x)) = '1'" are not supported
+ }
+
+ @Override
public boolean canRestrictSelector(SelectorImpl s) {
return propertyValue.canRestrictSelector(s);
}
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/LowerCaseImpl.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/LowerCaseImpl.java?rev=1747703&r1=1747702&r2=1747703&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/LowerCaseImpl.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/LowerCaseImpl.java
Fri Jun 10 12:49:32 2016
@@ -94,6 +94,7 @@ public class LowerCaseImpl extends Dynam
public void restrict(FilterImpl f, Operator operator, PropertyValue v) {
// LOWER(x) implies x is not null
operand.restrict(f, Operator.NOT_EQUAL, null);
+ operand.restrictFunction(f, "lower", operator, v);
}
@Override
@@ -103,6 +104,11 @@ public class LowerCaseImpl extends Dynam
}
@Override
+ public void restrictFunction(FilterImpl f, String functionName, Operator
operator, PropertyValue v) {
+ // optimizations of the type "lower(upper(x)) = 'x'" are not currently
supported
+ }
+
+ @Override
public boolean canRestrictSelector(SelectorImpl s) {
return operand.canRestrictSelector(s);
}
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/NativeFunctionImpl.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/NativeFunctionImpl.java?rev=1747703&r1=1747702&r2=1747703&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/NativeFunctionImpl.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/NativeFunctionImpl.java
Fri Jun 10 12:49:32 2016
@@ -35,8 +35,11 @@ public class NativeFunctionImpl extends
private final Logger log = LoggerFactory.getLogger(getClass());
+ /**
+ * The prefix for native function restrictions (native, similar,
spellcheck, suggest).
+ */
public static final String NATIVE_PREFIX = "native*";
-
+
private final String selectorName;
private final String language;
private final StaticOperandImpl nativeSearchExpression;
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/NodeLocalNameImpl.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/NodeLocalNameImpl.java?rev=1747703&r1=1747702&r2=1747703&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/NodeLocalNameImpl.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/NodeLocalNameImpl.java
Fri Jun 10 12:49:32 2016
@@ -85,7 +85,6 @@ public class NodeLocalNameImpl extends D
if (v == null) {
return;
}
-
String name = NodeNameImpl.getName(query, v);
if (name != null && f.getSelector().equals(selector)
&& NodeNameImpl.supportedOperator(operator)) {
@@ -98,6 +97,22 @@ public class NodeLocalNameImpl extends D
public void restrictList(FilterImpl f, List<PropertyValue> list) {
// optimizations of type "LOCALNAME(..) IN(A, B)" are not supported
}
+
+ @Override
+ public void restrictFunction(FilterImpl f, String functionName, Operator
operator, PropertyValue v) {
+ // optimizations of the type "lower(LOCALNAME(x)) = 'x'"
+ if (v == null) {
+ return;
+ }
+ String name = NodeNameImpl.getName(query, v);
+ if (name != null && f.getSelector().equals(selector)
+ && NodeNameImpl.supportedOperator(operator)) {
+ String restrictionName =
QueryConstants.FUNCTION_RESTRICTION_PREFIX +
+ functionName + "*@" +
QueryConstants.RESTRICTION_LOCAL_NAME;
+ f.restrictProperty(restrictionName,
+ operator, PropertyValues.newString(name));
+ }
+ }
@Override
public boolean supportsRangeConditions() {
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/NodeNameImpl.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/NodeNameImpl.java?rev=1747703&r1=1747702&r2=1747703&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/NodeNameImpl.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/NodeNameImpl.java
Fri Jun 10 12:49:32 2016
@@ -103,6 +103,22 @@ public class NodeNameImpl extends Dynami
}
@Override
+ public void restrictFunction(FilterImpl f, String functionName, Operator
operator, PropertyValue v) {
+ if (v == null) {
+ return;
+ }
+ String name = getName(query, v);
+ if (name != null && f.getSelector().equals(selector)
+ && NodeNameImpl.supportedOperator(operator)) {
+ String localName = NodeLocalNameImpl.getLocalName(name);
+ String restrictionName =
QueryConstants.FUNCTION_RESTRICTION_PREFIX +
+ functionName + "*@" +
QueryConstants.RESTRICTION_LOCAL_NAME;
+ f.restrictProperty(restrictionName,
+ operator, PropertyValues.newString(localName));
+ }
+ }
+
+ @Override
public boolean canRestrictSelector(SelectorImpl s) {
return s.equals(selector);
}
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/PropertyValueImpl.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/PropertyValueImpl.java?rev=1747703&r1=1747702&r2=1747703&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/PropertyValueImpl.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/PropertyValueImpl.java
Fri Jun 10 12:49:32 2016
@@ -31,6 +31,7 @@ import org.apache.jackrabbit.oak.query.Q
import org.apache.jackrabbit.oak.query.SQL2Parser;
import org.apache.jackrabbit.oak.query.index.FilterImpl;
import org.apache.jackrabbit.oak.spi.query.Filter.PathRestriction;
+import org.apache.jackrabbit.oak.spi.query.QueryConstants;
/**
* A property expression.
@@ -140,6 +141,16 @@ public class PropertyValueImpl extends D
f.restrictPropertyAsList(pn, list);
}
}
+
+ @Override
+ public void restrictFunction(FilterImpl f, String functionName, Operator
operator, PropertyValue v) {
+ if (f.getSelector().equals(selector)) {
+ String pn = normalizePropertyName(propertyName);
+ String restrictionName =
QueryConstants.FUNCTION_RESTRICTION_PREFIX +
+ functionName + "*@" + pn;
+ f.restrictProperty(restrictionName, operator, v, propertyType);
+ }
+ }
@Override
public boolean canRestrictSelector(SelectorImpl s) {
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/UpperCaseImpl.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/UpperCaseImpl.java?rev=1747703&r1=1747702&r2=1747703&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/UpperCaseImpl.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/UpperCaseImpl.java
Fri Jun 10 12:49:32 2016
@@ -80,6 +80,7 @@ public class UpperCaseImpl extends Dynam
public void restrict(FilterImpl f, Operator operator, PropertyValue v) {
// UPPER(x) implies x is not null
operand.restrict(f, Operator.NOT_EQUAL, null);
+ operand.restrictFunction(f, "upper", operator, v);
}
@Override
@@ -87,6 +88,11 @@ public class UpperCaseImpl extends Dynam
// "UPPER(x) IN (A, B)" implies x is not null
operand.restrict(f, Operator.NOT_EQUAL, null);
}
+
+ @Override
+ public void restrictFunction(FilterImpl f, String functionName, Operator
operator, PropertyValue v) {
+ // optimizations of the type "lower(upper(x)) = 'x'" are not supported
+ }
@Override
public boolean canRestrictSelector(SelectorImpl s) {
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/query/QueryConstants.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/query/QueryConstants.java?rev=1747703&r1=1747702&r2=1747703&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/query/QueryConstants.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/query/QueryConstants.java
Fri Jun 10 12:49:32 2016
@@ -26,5 +26,22 @@ public abstract class QueryConstants {
* via NAME and LOCALNAME functions
*/
public static final String RESTRICTION_LOCAL_NAME = ":localname";
+
+ /**
+ * The prefix for restrictions for function-based indexes, for example
+ * upper(propertyName). Syntax: "function*expression". In order to support
+ * all kinds of expressions in the future (including nested expressions and
+ * so on), the format for the expression is written in the Polish notation
+ * (the RPN, reversed), with "*" as delimiter (as property names may not
+ * contain "*"), and "@" in front of each property name to distinguish
+ * between property names and functions. Literals are quoted. Examples: The
+ * expression "lower(lastName)" is converted to "function*lower {@literal
@}
+ * lastName". The expression "lower(lastName)" is converted to
+ * "lower(upper(lastName))" is converted to "function*lower*upper*
+ * {@literal @}lastName". The condition
+ * "firstName+' '+lastName = 'Tim Cook'" would be "function*+*+ {@literal
@}
+ * firstName*' ' {@literal @}lastName.
+ */
+ public static final String FUNCTION_RESTRICTION_PREFIX = "function*";
}
\ No newline at end of file
Modified:
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/FilterTest.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/FilterTest.java?rev=1747703&r1=1747702&r2=1747703&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/FilterTest.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/FilterTest.java
Fri Jun 10 12:49:32 2016
@@ -52,6 +52,49 @@ public class FilterTest {
}
@Test
+ public void functionBasedIndex() throws Exception {
+ String sql2 = "select [jcr:path] from [nt:base] where lower([test]) =
'hello'";
+ assertEquals("Filter(query=select [jcr:path] from [nt:base] " +
+ "where lower([test]) = 'hello', " +
+ "path=*, property=[" +
+ "function*lower*@test=[hello], " +
+ "test=[is not null]])", createFilterSQL(sql2).toString());
+
+ sql2 = "select [jcr:path] from [nt:base] where upper([test]) =
'HELLO'";
+ assertEquals("Filter(query=select [jcr:path] from [nt:base] " +
+ "where upper([test]) = 'HELLO', " +
+ "path=*, property=[" +
+ "function*upper*@test=[HELLO], " +
+ "test=[is not null]])", createFilterSQL(sql2).toString());
+
+ sql2 = "select [jcr:path] from [nt:base] where upper(name()) =
'ACME:TEST'";
+ assertEquals("Filter(query=select [jcr:path] from [nt:base] " +
+ "where upper(name()) = 'ACME:TEST', " +
+ "path=*, property=[" +
+ "function*upper*@:localname=[TEST]])",
createFilterSQL(sql2).toString());
+
+ sql2 = "select [jcr:path] from [nt:base] where lower(localname()) =
'test'";
+ assertEquals("Filter(query=select [jcr:path] from [nt:base] " +
+ "where lower(localname()) = 'test', " +
+ "path=*, property=[" +
+ "function*lower*@:localname=[test]])",
createFilterSQL(sql2).toString());
+
+ sql2 = "select [jcr:path] from [nt:base] where length([test]) <= 10";
+ assertEquals("Filter(query=select [jcr:path] from [nt:base] " +
+ "where length([test]) <= 10, " +
+ "path=*, property=[test=[is not null], " +
+ "function*length*@test=[..10]]])",
createFilterSQL(sql2).toString());
+
+ sql2 = "select [jcr:path] from [nt:base] where length([test]) > 2";
+ assertEquals("Filter(query=select [jcr:path] from [nt:base] " +
+ "where length([test]) > 2, " +
+ "path=*, property=[test=[is not null], " +
+ "function*length*@test=[(2..]])",
createFilterSQL(sql2).toString());
+
+
+ }
+
+ @Test
public void oak4170() throws ParseException {
String sql2 = "select * from [nt:unstructured] where
CONTAINS([jcr:content/metadata/comment], 'december')";
Filter f = createFilterSQL(sql2);
Modified:
jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/IndexPlanner.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/IndexPlanner.java?rev=1747703&r1=1747702&r2=1747703&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/IndexPlanner.java
(original)
+++
jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/IndexPlanner.java
Fri Jun 10 12:49:32 2016
@@ -154,6 +154,10 @@ class IndexPlanner {
if (QueryConstants.RESTRICTION_LOCAL_NAME.equals(name)) {
continue;
}
+ if
(name.startsWith(QueryConstants.FUNCTION_RESTRICTION_PREFIX)) {
+ // TODO support function-based indexes
+ continue;
+ }
if (QueryImpl.REP_FACET.equals(pr.propertyName)) {
String value = pr.first.getValue(Type.STRING);
facetFields.add(FacetHelper.parseFacetField(value));