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 2013/07/15 11:07:11 UTC

svn commit: r1503146 - in /jackrabbit/oak/trunk/oak-core/src: main/java/org/apache/jackrabbit/oak/query/ast/ main/java/org/apache/jackrabbit/oak/query/fulltext/ test/java/org/apache/jackrabbit/oak/query/ test/java/org/apache/jackrabbit/oak/query/ast/

Author: thomasm
Date: Mon Jul 15 09:07:10 2013
New Revision: 1503146

URL: http://svn.apache.org/r1503146
Log:
OAK-890 Query: advanced fulltext search conditions

Modified:
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/AstElement.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/AstVisitorBase.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/FullTextSearchImpl.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/fulltext/FullTextAnd.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/fulltext/FullTextExpression.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/fulltext/FullTextOr.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/fulltext/FullTextParser.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/fulltext/FullTextTerm.java
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/SQL2ParserTest.java
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/ast/FullTextTest.java

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/AstElement.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/AstElement.java?rev=1503146&r1=1503145&r2=1503146&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/AstElement.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/AstElement.java Mon Jul 15 09:07:10 2013
@@ -56,6 +56,8 @@ abstract class AstElement {
      */
     protected String validateAndNormalizePath(String path) {
         // TODO normalize the path (remove superfluous ".." and "." where possible)
+        // possibly using
+        //  PropertyValues.getOakPath(name, query.getNamePathMapper());
         query.validatePath(path);
         return path;
     }

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/AstVisitorBase.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/AstVisitorBase.java?rev=1503146&r1=1503145&r2=1503146&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/AstVisitorBase.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/AstVisitorBase.java Mon Jul 15 09:07:10 2013
@@ -69,8 +69,8 @@ public abstract class AstVisitorBase imp
      */
     @Override
     public boolean visit(JoinImpl node) {
-        node.getRight().accept(this);
         node.getLeft().accept(this);
+        node.getRight().accept(this);
         node.getJoinCondition().accept(this);
         return true;
     }

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/FullTextSearchImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/FullTextSearchImpl.java?rev=1503146&r1=1503145&r2=1503146&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/FullTextSearchImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/FullTextSearchImpl.java Mon Jul 15 09:07:10 2013
@@ -69,7 +69,6 @@ public class FullTextSearchImpl extends 
         } else {
             this.propertyName = propertyName;
         }
-
         this.fullTextSearchExpression = fullTextSearchExpression;
     }
 
@@ -95,6 +94,11 @@ public class FullTextSearchImpl extends 
         if (relativePath != null) {
             propertyName = relativePath + "/" + propertyName;
         }
+        
+        // temporary workaround to support using an index for
+        // "contains(*, 'x') or contains(a, x') or contains(b, 'x')"
+        // propertyName = "*";
+        
         builder.append(quote(propertyName));
         builder.append(", ");
         builder.append(getFullTextSearchExpression());
@@ -122,6 +126,9 @@ public class FullTextSearchImpl extends 
 
     @Override
     public boolean evaluate() {
+        // disable evaluation if a fulltext index is used, as
+        // we don't know what exact options are used in the fulltext index
+        // (stop word, special characters,...)
         if (selector.index instanceof FulltextQueryIndex) {
             return true;
         }
@@ -156,13 +163,9 @@ public class FullTextSearchImpl extends 
                 }
             }
         }
-        // TODO fulltext conditions: need a way to disable evaluation
-        // if a fulltext index is used, to avoid filtering too much
-        // (we don't know what exact options are used in the fulltext index)
-        // (stop word, special characters,...)
         PropertyValue v = fullTextSearchExpression.currentValue();
         try {
-            FullTextExpression expr = FullTextParser.parse(v.getValue(Type.STRING));
+            FullTextExpression expr = FullTextParser.parse(propertyName, v.getValue(Type.STRING));
             return expr.evaluate(buff.toString());
         } catch (ParseException e) {
             throw new IllegalArgumentException("Invalid expression: " + fullTextSearchExpression, e);

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/fulltext/FullTextAnd.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/fulltext/FullTextAnd.java?rev=1503146&r1=1503145&r2=1503146&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/fulltext/FullTextAnd.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/fulltext/FullTextAnd.java Mon Jul 15 09:07:10 2013
@@ -19,13 +19,18 @@
 package org.apache.jackrabbit.oak.query.fulltext;
 
 import java.util.ArrayList;
+import java.util.LinkedHashSet;
 
 /**
  * A fulltext "and" condition.
  */
 public class FullTextAnd extends FullTextExpression {
     
-    public ArrayList<FullTextExpression> list = new ArrayList<FullTextExpression>();
+    public final ArrayList<FullTextExpression> list;
+    
+    public FullTextAnd(ArrayList<FullTextExpression> list) {
+        this.list = list;
+    }
 
     @Override
     public boolean evaluate(String value) {
@@ -39,7 +44,17 @@ public class FullTextAnd extends FullTex
 
     @Override
     public FullTextExpression simplify() {
-        return list.size() == 1 ? list.get(0) : this;
+        // remove duplicates
+        LinkedHashSet<FullTextExpression> newList = new LinkedHashSet<FullTextExpression>();
+        for (int i = 0; i < list.size(); i++) {
+            newList.add(list.get(i).simplify());
+        }
+        if (newList.size() == 1) {
+            return newList.iterator().next();
+        }
+        ArrayList<FullTextExpression> l = new ArrayList<FullTextExpression>(newList.size());
+        l.addAll(newList);
+        return new FullTextAnd(l);
     }
 
     @Override

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/fulltext/FullTextExpression.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/fulltext/FullTextExpression.java?rev=1503146&r1=1503145&r2=1503146&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/fulltext/FullTextExpression.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/fulltext/FullTextExpression.java Mon Jul 15 09:07:10 2013
@@ -23,10 +23,62 @@ package org.apache.jackrabbit.oak.query.
  */
 public abstract class FullTextExpression {
     
-    public static final int PRECEDENCE_OR = 1, PRECEDENCE_AND = 2, PRECEDENCE_TERM = 3;
+    /**
+     * The operator precedence for OR conditions.
+     */
+    public static final int PRECEDENCE_OR = 1;
+
+    /**
+     * The operator precedence for AND conditions.
+     */
+    public static final int PRECEDENCE_AND = 2;
     
+    /**
+     * The operator precedence for terms.
+     */
+    public static final int PRECEDENCE_TERM = 3;
+
+    /**
+     * Get the operator precedence.
+     * 
+     * @return the precedence
+     */
     public abstract int getPrecedence();
+    
+    /**
+     * Evaluate whether the value matches the condition.
+     * 
+     * @param value the value
+     * @return true if it matches
+     */
     public abstract boolean evaluate(String value);
+    
+    /**
+     * Simplify the expression if possible (removing duplicate conditions).
+     * 
+     * @return the simplified expression
+     */
     abstract FullTextExpression simplify();
     
+    /**
+     * Get the string representation of the condition.
+     */
+    @Override
+    public abstract String toString();
+    
+    @Override
+    public boolean equals(Object other) {
+        if (this == other) {
+            return true;
+        } else if (!(other instanceof FullTextExpression)) {
+            return false;
+        }
+        return toString().equals(other.toString());
+    }
+    
+    @Override
+    public int hashCode() {
+        return toString().hashCode();
+    }
+    
 }
\ No newline at end of file

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/fulltext/FullTextOr.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/fulltext/FullTextOr.java?rev=1503146&r1=1503145&r2=1503146&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/fulltext/FullTextOr.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/fulltext/FullTextOr.java Mon Jul 15 09:07:10 2013
@@ -19,12 +19,18 @@
 package org.apache.jackrabbit.oak.query.fulltext;
 
 import java.util.ArrayList;
+import java.util.LinkedHashSet;
 
 /**
  * A fulltext "or" condition.
  */
 public class FullTextOr extends FullTextExpression {
-    public ArrayList<FullTextExpression> list = new ArrayList<FullTextExpression>();
+    
+    public final ArrayList<FullTextExpression> list;
+    
+    public FullTextOr(ArrayList<FullTextExpression> list) {
+        this.list = list;
+    }
 
     @Override
     public boolean evaluate(String value) {
@@ -38,7 +44,17 @@ public class FullTextOr extends FullText
 
     @Override
     public FullTextExpression simplify() {
-        return list.size() == 1 ? list.get(0).simplify() : this;
+        // remove duplicates
+        LinkedHashSet<FullTextExpression> newList = new LinkedHashSet<FullTextExpression>();
+        for (int i = 0; i < list.size(); i++) {
+            newList.add(list.get(i).simplify());
+        }
+        if (newList.size() == 1) {
+            return newList.iterator().next();
+        }
+        ArrayList<FullTextExpression> l = new ArrayList<FullTextExpression>(newList.size());
+        l.addAll(newList);
+        return new FullTextOr(l);
     }
 
     @Override

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/fulltext/FullTextParser.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/fulltext/FullTextParser.java?rev=1503146&r1=1503145&r2=1503146&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/fulltext/FullTextParser.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/fulltext/FullTextParser.java Mon Jul 15 09:07:10 2013
@@ -19,6 +19,7 @@
 package org.apache.jackrabbit.oak.query.fulltext;
 
 import java.text.ParseException;
+import java.util.ArrayList;
 
 
 /**
@@ -35,39 +36,43 @@ import java.text.ParseException;
  */
 public class FullTextParser {
 
-    String text;
-    int parseIndex;
+    private String propertyName;
+    private String text;
+    private int parseIndex;
 
-    public static FullTextExpression parse(String text) throws ParseException {
+    public static FullTextExpression parse(String propertyName, String text) throws ParseException {
         FullTextParser p = new FullTextParser();
+        p.propertyName = propertyName;
         p.text = text;
         FullTextExpression e = p.parseOr();
         return e;
     }
 
     FullTextExpression parseOr() throws ParseException {
-        FullTextOr or = new FullTextOr();
-        or.list.add(parseAnd());
+        ArrayList<FullTextExpression> list = new ArrayList<FullTextExpression>();
+        list.add(parseAnd());
         while (parseIndex < text.length()) {
             if (text.substring(parseIndex).startsWith("OR ")) {
                 parseIndex += 3;
-                or.list.add(parseAnd());
+                list.add(parseAnd());
             } else {
                 break;
             }
         }
+        FullTextOr or = new FullTextOr(list);
         return or.simplify();
     }
 
     FullTextExpression parseAnd() throws ParseException {
-        FullTextAnd and = new FullTextAnd();
-        and.list.add(parseTerm());
+        ArrayList<FullTextExpression> list = new ArrayList<FullTextExpression>();
+        list.add(parseTerm());
         while (parseIndex < text.length()) {
             if (text.substring(parseIndex).startsWith("OR ")) {
                 break;
             }
-            and.list.add(parseTerm());
+            list.add(parseTerm());
         }
+        FullTextAnd and = new FullTextAnd(list);
         return and.simplify();
     }
 
@@ -149,7 +154,7 @@ public class FullTextParser {
             throw getSyntaxError("term");
         }
         String text = buff.toString();
-        FullTextTerm term = new FullTextTerm(text, not, escaped, boost);
+        FullTextTerm term = new FullTextTerm(propertyName, text, not, escaped, boost);
         return term.simplify();
     }
 

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/fulltext/FullTextTerm.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/fulltext/FullTextTerm.java?rev=1503146&r1=1503145&r2=1503146&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/fulltext/FullTextTerm.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/fulltext/FullTextTerm.java Mon Jul 15 09:07:10 2013
@@ -23,12 +23,14 @@ package org.apache.jackrabbit.oak.query.
  */
 public class FullTextTerm extends FullTextExpression {
     private final boolean not;
+    private final String propertyName;
     private final String text;
     private final String filteredText;
     private final String boost;
     private final LikePattern like;
 
-    public FullTextTerm(String text, boolean not, boolean escaped, String boost) {
+    public FullTextTerm(String propertyName, String text, boolean not, boolean escaped, String boost) {
+        this.propertyName = propertyName;
         this.text = text;
         this.not = not;
         this.boost = boost;
@@ -71,7 +73,7 @@ public class FullTextTerm extends FullTe
 
     @Override
     public boolean evaluate(String value) {
-        // for testFulltextIntercapSQL
+        // toLowerCase for testFulltextIntercapSQL
         value = value.toLowerCase();
         if (like != null) {
             return like.matches(value);
@@ -94,6 +96,11 @@ public class FullTextTerm extends FullTe
         if (not) {
             buff.append('-');
         }
+        if (propertyName != null && "*".equals(propertyName)) {
+            // TODO support property name conditions
+            // (currently disabled)
+            buff.append(propertyName).append(':');
+        }
         buff.append('\"');
         for (int i = 0; i < text.length(); i++) {
             char c = text.charAt(i);
@@ -111,6 +118,10 @@ public class FullTextTerm extends FullTe
         return buff.toString();
     }
     
+    public String getPropertyName() {
+        return propertyName;
+    }
+    
     @Override
     public int getPrecedence() {
         return PRECEDENCE_TERM;

Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/SQL2ParserTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/SQL2ParserTest.java?rev=1503146&r1=1503145&r2=1503146&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/SQL2ParserTest.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/SQL2ParserTest.java Mon Jul 15 09:07:10 2013
@@ -50,11 +50,7 @@ public class SQL2ParserTest {
                 .convert("/jcr:root/test/*/nt:resource[@jcr:encoding]"));
     }
 
-    /**
-     * @see <a
-     *      href="https://issues.apache.org/jira/browse/OAK-OAK-830">OAK-OAK-830:
-     *      XPathToSQL2Converter fails to wrap or clauses</a>
-     */
+    // see OAK-OAK-830: XPathToSQL2Converter fails to wrap or clauses
     @Test
     public void testUnwrappedOr() throws ParseException {
         String q = new XPathToSQL2Converter()
@@ -62,4 +58,5 @@ public class SQL2ParserTest {
         String token = "and (b.[type] = 't1' or b.[type] = 't2' or b.[type] = 't3')";
         assertTrue(q.contains(token));
     }
+    
 }

Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/ast/FullTextTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/ast/FullTextTest.java?rev=1503146&r1=1503145&r2=1503146&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/ast/FullTextTest.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/ast/FullTextTest.java Mon Jul 15 09:07:10 2013
@@ -113,12 +113,12 @@ public class FullTextTest {
     }
     
     private static String convertPattern(String pattern) throws ParseException {
-        FullTextExpression e = FullTextParser.parse(pattern);
+        FullTextExpression e = FullTextParser.parse(null, pattern);
         return e.toString();
     }
 
     private static boolean test(String pattern, String value) throws ParseException {
-        FullTextExpression e = FullTextParser.parse(pattern);
+        FullTextExpression e = FullTextParser.parse(null, pattern);
         return e.evaluate(value);
     }