jackrabbit-oak-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From mreut...@apache.org
Subject svn commit: r1470434 - in /jackrabbit/oak/trunk/oak-core/src: main/java/org/apache/jackrabbit/oak/plugins/index/p2/ main/java/org/apache/jackrabbit/oak/spi/query/ test/java/org/apache/jackrabbit/oak/plugins/index/p2/
Date Mon, 22 Apr 2013 10:26:38 GMT
Author: mreutegg
Date: Mon Apr 22 10:26:38 2013
New Revision: 1470434

URL: http://svn.apache.org/r1470434
Log:
OAK-789: Support relative path in Property2Index

Added:
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/p2/RelativePathTest.java
  (with props)
Modified:
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/p2/Property2Index.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/query/Cursors.java

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/p2/Property2Index.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/p2/Property2Index.java?rev=1470434&r1=1470433&r2=1470434&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/p2/Property2Index.java
(original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/p2/Property2Index.java
Mon Apr 22 10:26:38 2013
@@ -23,6 +23,7 @@ import java.util.List;
 
 import org.apache.jackrabbit.oak.api.PropertyValue;
 import org.apache.jackrabbit.oak.api.Type;
+import org.apache.jackrabbit.oak.commons.PathUtils;
 import org.apache.jackrabbit.oak.spi.query.Cursor;
 import org.apache.jackrabbit.oak.spi.query.Cursors;
 import org.apache.jackrabbit.oak.spi.query.Filter;
@@ -110,16 +111,17 @@ class Property2Index implements QueryInd
     public double getCost(Filter filter, NodeState root) {
         Property2IndexLookup lookup = new Property2IndexLookup(root);
         for (PropertyRestriction pr : filter.getPropertyRestrictions()) {
+            String propertyName = PathUtils.getName(pr.propertyName);
             // TODO support indexes on a path
             // currently, only indexes on the root node are supported
-            if (lookup.isIndexed(pr.propertyName, "/", filter)) {
+            if (lookup.isIndexed(propertyName, "/", filter)) {
                 if (pr.firstIncluding && pr.lastIncluding
                     && pr.first != null && pr.first.equals(pr.last)) {
                     // "[property] = $value"
-                    return lookup.getCost(filter, pr.propertyName, pr.first);
+                    return lookup.getCost(filter, propertyName, pr.first);
                 } else if (pr.first == null && pr.last == null) {
                     // "[property] is not null"
-                    return lookup.getCost(filter, pr.propertyName, null);
+                    return lookup.getCost(filter, propertyName, null);
                 }
             }
         }
@@ -132,19 +134,22 @@ class Property2Index implements QueryInd
         Iterable<String> paths = null;
 
         Property2IndexLookup lookup = new Property2IndexLookup(root);
+        int depth = 1;
         for (PropertyRestriction pr : filter.getPropertyRestrictions()) {
+            String propertyName = PathUtils.getName(pr.propertyName);
+            depth = PathUtils.getDepth(pr.propertyName);
             // TODO support indexes on a path
             // currently, only indexes on the root node are supported
-            if (lookup.isIndexed(pr.propertyName, "/", filter)) {
+            if (lookup.isIndexed(propertyName, "/", filter)) {
                 // equality
                 if (pr.firstIncluding && pr.lastIncluding
                     && pr.first != null && pr.first.equals(pr.last)) {
                     // "[property] = $value"
-                    paths = lookup.query(filter, pr.propertyName, pr.first);
+                    paths = lookup.query(filter, propertyName, pr.first);
                     break;
                 } else if (pr.first == null && pr.last == null) {
                     // "[property] is not null"
-                    paths = lookup.query(filter, pr.propertyName, null);
+                    paths = lookup.query(filter, propertyName, null);
                     break;
                 }
             }
@@ -152,7 +157,11 @@ class Property2Index implements QueryInd
         if (paths == null) {
             throw new IllegalStateException("Property index is used even when no index is
available for filter " + filter);
         }
-        return Cursors.newPathCursor(paths);
+        Cursor c = Cursors.newPathCursor(paths);
+        if (depth > 1) {
+            c = Cursors.newAncestorCursor(c, depth - 1);
+        }
+        return c;
     }
     
     @Override
@@ -160,14 +169,15 @@ class Property2Index implements QueryInd
         StringBuilder buff = new StringBuilder("p2");
         Property2IndexLookup lookup = new Property2IndexLookup(root);
         for (PropertyRestriction pr : filter.getPropertyRestrictions()) {
+            String propertyName = PathUtils.getName(pr.propertyName);
             // TODO support indexes on a path
             // currently, only indexes on the root node are supported
-            if (lookup.isIndexed(pr.propertyName, "/", filter)) {
+            if (lookup.isIndexed(propertyName, "/", filter)) {
                 if (pr.firstIncluding && pr.lastIncluding
                     && pr.first != null && pr.first.equals(pr.last)) {
-                    buff.append(' ').append(pr.propertyName).append('=').append(pr.first);
+                    buff.append(' ').append(propertyName).append('=').append(pr.first);
                 } else if (pr.first == null && pr.last == null) {
-                    buff.append(' ').append(pr.propertyName);
+                    buff.append(' ').append(propertyName);
                 }
             }
         }

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/query/Cursors.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/query/Cursors.java?rev=1470434&r1=1470433&r2=1470434&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/query/Cursors.java
(original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/query/Cursors.java
Mon Apr 22 10:26:38 2013
@@ -33,10 +33,13 @@ import org.apache.jackrabbit.oak.spi.sta
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.google.common.base.Function;
 import com.google.common.base.Predicate;
 import com.google.common.collect.Iterators;
 import com.google.common.collect.Queues;
 
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
 import static org.apache.jackrabbit.oak.commons.PathUtils.isAbsolute;
 
 /**
@@ -55,7 +58,7 @@ public class Cursors {
      * @return the Cursor.
      */
     public static Cursor newPathCursor(Iterable<String> paths) {
-        return new PathCursor(paths, true);
+        return new PathCursor(paths.iterator(), true);
     }
     
     /**
@@ -66,7 +69,7 @@ public class Cursors {
      * @return the Cursor.
      */
     public static Cursor newPathCursorDistinct(Iterable<String> paths) {
-        return new PathCursor(paths, true);
+        return new PathCursor(paths.iterator(), true);
     }
 
     /**
@@ -81,7 +84,24 @@ public class Cursors {
                                              NodeState rootState) {
         return new TraversingCursor(filter, rootState);
     }
-    
+
+    /**
+     * Returns a cursor wrapper, which returns the ancestor rows at the given
+     * <code>level</code> of the wrapped cursor <code>c</code>. With
+     * <code>level</code> e.g. set to <code>1</code>, the returned
cursor
+     * iterates over the parent rows of the passed cursor <code>c</code>. The
+     * returned cursor guarantees distinct rows.
+     *
+     * @param c the cursor to wrap.
+     * @param level the ancestor level. Must be >= 1.
+     * @return cursor over the ancestors of <code>c</code> at <code>level</code>.
+     */
+    public static Cursor newAncestorCursor(Cursor c, int level) {
+        checkNotNull(c);
+        checkArgument(level >= 1);
+        return new AncestorCursor(c, level);
+    }
+
     /**
      * A Cursor implementation where the remove method throws an
      * UnsupportedOperationException.
@@ -95,6 +115,36 @@ public class Cursors {
         
     }
 
+    private static class AncestorCursor extends PathCursor {
+
+        public AncestorCursor(Cursor cursor, int level) {
+            super(transform(cursor, level), true);
+        }
+
+        private static Iterator<String> transform(Cursor cursor, final int level) {
+            Iterator<String> unfiltered = Iterators.transform(cursor,
+                    new Function<IndexRow, String>() {
+                @Override
+                public String apply(@Nullable IndexRow input) {
+                    return input != null ? input.getPath() : null;
+                }
+            });
+            Iterator<String> filtered = Iterators.filter(unfiltered,
+                    new Predicate<String>() {
+                @Override
+                public boolean apply(@Nullable String input) {
+                    return input != null && PathUtils.getDepth(input) >= level;
+                }
+            });
+            return Iterators.transform(filtered, new Function<String, String>() {
+                @Override
+                public String apply(String input) {
+                    return PathUtils.getAncestorPath(input, level);
+                }
+            });
+        }
+    }
+
     /**
      * <code>PathCursor</code> implements a simple {@link Cursor} that iterates
      * over a {@link String} based path {@link Iterable}.
@@ -103,8 +153,8 @@ public class Cursors {
 
         private final Iterator<String> iterator;
 
-        public PathCursor(Iterable<String> paths, boolean distinct) {
-            Iterator<String> it = paths.iterator();
+        public PathCursor(Iterator<String> paths, boolean distinct) {
+            Iterator<String> it = paths;
             if (distinct) {
                 it = Iterators.filter(it, new Predicate<String>() {
                     

Added: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/p2/RelativePathTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/p2/RelativePathTest.java?rev=1470434&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/p2/RelativePathTest.java
(added)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/p2/RelativePathTest.java
Mon Apr 22 10:26:38 2013
@@ -0,0 +1,92 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.oak.plugins.index.p2;
+
+import java.util.List;
+
+import javax.jcr.query.Query;
+
+import org.apache.jackrabbit.oak.Oak;
+import org.apache.jackrabbit.oak.api.ContentRepository;
+import org.apache.jackrabbit.oak.api.Tree;
+import org.apache.jackrabbit.oak.plugins.index.IndexUtils;
+import org.apache.jackrabbit.oak.plugins.nodetype.write.InitialContent;
+import org.apache.jackrabbit.oak.query.AbstractQueryTest;
+import org.apache.jackrabbit.oak.spi.lifecycle.RepositoryInitializer;
+import org.apache.jackrabbit.oak.spi.security.OpenSecurityProvider;
+import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+import org.junit.Test;
+
+import com.google.common.collect.ImmutableList;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * <code>RelativePathTest</code>...
+ */
+public class RelativePathTest extends AbstractQueryTest {
+
+    @Override
+    protected ContentRepository createRepository() {
+        return new Oak().with(new InitialContent())
+                .with(new RepositoryInitializer() {
+                    @Override
+                    public NodeState initialize(NodeState state) {
+                        NodeBuilder root = state.builder();
+                        NodeBuilder index = IndexUtils.getOrCreateOakIndex(root);
+                        IndexUtils.createIndexDefinition(index, "myProp", true,
+                                false, ImmutableList.<String>of("myProp"), null);
+                        return root.getNodeState();
+                    }
+                })
+                .with(new OpenSecurityProvider())
+                .with(new Property2IndexProvider())
+                .with(new Property2IndexHookProvider())
+                .createContentRepository();
+    }
+
+    @Test
+    public void query() throws Exception {
+        Tree t = root.getTree("/");
+        t.addChild("a").addChild("n").setProperty("myProp", "foo");
+        t.addChild("b").addChild("n").setProperty("myProp", "bar");
+        t.addChild("c").addChild("x").setProperty("myProp", "foo");
+        t.setProperty("myProp", "foo");
+        root.commit();
+        List<String> paths = executeQuery(
+                "select [jcr:path] from [nt:base] where [n/myProp] is not null",
+                Query.JCR_SQL2);
+        assertEquals(2, paths.size());
+        assertTrue(paths.contains("/a"));
+        assertTrue(paths.contains("/b"));
+
+        List<String> lines = executeQuery(
+                "explain select [jcr:path] from [nt:base] where [n/myProp] is not null",
+                Query.JCR_SQL2);
+        assertEquals(1, lines.size());
+        // make sure it used the p2 index
+        assertTrue(lines.get(0).contains("p2 myProp"));
+
+        paths = executeQuery(
+                "select [jcr:path] from [nt:base] where [n/myProp] = 'foo'",
+                Query.JCR_SQL2);
+        assertEquals(1, paths.size());
+        assertTrue(paths.contains("/a"));
+    }
+}

Propchange: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/p2/RelativePathTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/p2/RelativePathTest.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision Rev URL



Mime
View raw message