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 2012/04/24 14:17:28 UTC
svn commit: r1329667 - in /jackrabbit/oak/trunk/oak-core/src:
main/java/org/apache/jackrabbit/mk/index/
main/java/org/apache/jackrabbit/oak/api/
main/java/org/apache/jackrabbit/oak/core/
main/java/org/apache/jackrabbit/oak/query/ main/java/org/apache/j...
Author: thomasm
Date: Tue Apr 24 12:17:27 2012
New Revision: 1329667
URL: http://svn.apache.org/viewvc?rev=1329667&view=rev
Log:
OAK-28 Query implementation (index provider, property index)
Added:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/index/PropertyContentIndex.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/index/QueryIndexProvider.java
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/mk/index/BTree.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/mk/index/Index.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/mk/index/IndexWrapper.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/mk/index/Indexer.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/mk/index/PrefixIndex.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/mk/index/PropertyIndex.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/QueryEngine.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/KernelContentRepository.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/Query.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryEngineImpl.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SelectorImpl.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/index/Filter.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/index/QueryIndex.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/index/TraversingIndex.java
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/mk/index/IndexTest.java
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/mk/index/PrefixIndexTest.java
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/mk/index/PropertyIndexTest.java
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/AbstractQueryTest.java
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/QueryTest.java
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/index/FilterTest.java
jackrabbit/oak/trunk/oak-core/src/test/resources/org/apache/jackrabbit/oak/query/queryTest.txt
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/mk/index/BTree.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/mk/index/BTree.java?rev=1329667&r1=1329666&r2=1329667&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/mk/index/BTree.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/mk/index/BTree.java Tue Apr 24 12:17:27 2012
@@ -288,4 +288,8 @@ public class BTree {
return minSize + minSize + 1;
}
+ boolean isUnique() {
+ return unique;
+ }
+
}
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/mk/index/Index.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/mk/index/Index.java?rev=1329667&r1=1329666&r2=1329667&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/mk/index/Index.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/mk/index/Index.java Tue Apr 24 12:17:27 2012
@@ -16,6 +16,7 @@
*/
package org.apache.jackrabbit.mk.index;
+import java.util.Iterator;
import org.apache.jackrabbit.mk.simple.NodeImpl;
/**
@@ -51,4 +52,21 @@ public interface Index {
void addOrRemoveProperty(String nodePath, String propertyName,
String value, boolean add);
+ /**
+ * Get an iterator over the paths for the given value. For unique
+ * indexes, the iterator will contain at most one element.
+ *
+ * @param value the value, or null to return all indexed rows
+ * @param revision the revision
+ * @return an iterator of the paths (an empty iterator if not found)
+ */
+ Iterator<String> getPaths(String value, String revision);
+
+ /**
+ * Whether each value may only appear once in the index.
+ *
+ * @return true if unique
+ */
+ boolean isUnique();
+
}
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/mk/index/IndexWrapper.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/mk/index/IndexWrapper.java?rev=1329667&r1=1329666&r2=1329667&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/mk/index/IndexWrapper.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/mk/index/IndexWrapper.java Tue Apr 24 12:17:27 2012
@@ -50,6 +50,7 @@ public class IndexWrapper extends MicroK
public IndexWrapper(MicroKernel mk) {
this.mk = MicroKernelWrapperBase.wrap(mk);
this.indexer = new Indexer(mk);
+ indexer.init();
}
@Override
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/mk/index/Indexer.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/mk/index/Indexer.java?rev=1329667&r1=1329666&r2=1329667&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/mk/index/Indexer.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/mk/index/Indexer.java Tue Apr 24 12:17:27 2012
@@ -26,17 +26,21 @@ import org.apache.jackrabbit.mk.simple.N
import org.apache.jackrabbit.mk.util.ExceptionFactory;
import org.apache.jackrabbit.mk.util.PathUtils;
import org.apache.jackrabbit.mk.util.SimpleLRUCache;
+import org.apache.jackrabbit.oak.query.index.PropertyContentIndex;
+import org.apache.jackrabbit.oak.query.index.QueryIndex;
+import org.apache.jackrabbit.oak.query.index.QueryIndexProvider;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
+import java.util.List;
import java.util.Map.Entry;
/**
* A index mechanism. An index is bound to a certain repository, and supports
* one or more indexes.
*/
-public class Indexer {
+public class Indexer implements QueryIndexProvider {
private static final boolean DISABLED = Boolean.getBoolean("mk.indexDisabled");
@@ -48,18 +52,33 @@ public class Indexer {
private HashMap<String, BTreePage> modified = new HashMap<String, BTreePage>();
private SimpleLRUCache<String, BTreePage> cache = SimpleLRUCache.newInstance(100);
private String readRevision;
+ private ArrayList<QueryIndexListener> listeners = new ArrayList<QueryIndexListener>();
public Indexer(MicroKernel mk, String indexRootNode) {
this.mk = mk;
+ this.indexRootNode = indexRootNode;
+ }
+
+ public Indexer(MicroKernel mk) {
+ this(mk, "/index");
+ }
+
+ @Override
+ public void init() {
if (!PathUtils.isAbsolute(indexRootNode)) {
indexRootNode = "/" + indexRootNode;
}
- this.indexRootNode = indexRootNode;
revision = mk.getHeadRevision();
readRevision = revision;
if (!mk.nodeExists(indexRootNode, revision)) {
JsopBuilder jsop = new JsopBuilder();
- jsop.tag('+').key(PathUtils.relativize("/", indexRootNode)).object().endObject();
+ String p = "/";
+ for (String e : PathUtils.elements(indexRootNode)) {
+ p = PathUtils.concat(p, e);
+ if (!mk.nodeExists(p, revision)) {
+ jsop.tag('+').key(PathUtils.relativize("/", p)).object().endObject().newline();
+ }
+ }
revision = mk.commit("/", jsop.toString(), revision, null);
} else {
String node = mk.getNodes(indexRootNode, revision, 0, 0, Integer.MAX_VALUE, null);
@@ -89,10 +108,6 @@ public class Indexer {
}
}
- public Indexer(MicroKernel mk) {
- this(mk, "/index");
- }
-
public PropertyIndex createPropertyIndex(String property, boolean unique) {
PropertyIndex index = new PropertyIndex(this, property, unique);
PropertyIndex existing = (PropertyIndex) indexes.get(index.getName());
@@ -100,6 +115,9 @@ public class Indexer {
return existing;
}
buildAndAddIndex(index);
+ for (QueryIndexListener l : listeners) {
+ l.added(new PropertyContentIndex(mk, index));
+ }
return index;
}
@@ -490,4 +508,28 @@ public class Indexer {
}
}
+ public List<QueryIndex> getQueryIndexes() {
+ ArrayList<QueryIndex> list = new ArrayList<QueryIndex>();
+ for (Index index : indexes.values()) {
+ QueryIndex qi = null;
+ if (index instanceof PropertyIndex) {
+ qi = new PropertyContentIndex(mk, (PropertyIndex) index);
+ } else if (index instanceof PrefixIndex) {
+ // TODO support prefix indexes?
+ }
+ list.add(qi);
+ }
+ return list;
+ }
+
+ @Override
+ public void addListener(QueryIndexListener listener) {
+ listeners.add(listener);
+ }
+
+ @Override
+ public void removeListener(QueryIndexListener listener) {
+ listeners.remove(listener);
+ }
+
}
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/mk/index/PrefixIndex.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/mk/index/PrefixIndex.java?rev=1329667&r1=1329666&r2=1329667&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/mk/index/PrefixIndex.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/mk/index/PrefixIndex.java Tue Apr 24 12:17:27 2012
@@ -108,6 +108,7 @@ public class PrefixIndex implements Inde
* @return an iterator of the paths (an empty iterator if not found)
* @throws IllegalArgumentException if the value doesn't start with the prefix
*/
+ @Override
public Iterator<String> getPaths(String value, String revision) {
if (!value.startsWith(prefix)) {
throw new IllegalArgumentException(
@@ -119,4 +120,9 @@ public class PrefixIndex implements Inde
return new Cursor.RangeIterator(c, v);
}
+ @Override
+ public boolean isUnique() {
+ return tree.isUnique();
+ }
+
}
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/mk/index/PropertyIndex.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/mk/index/PropertyIndex.java?rev=1329667&r1=1329666&r2=1329667&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/mk/index/PropertyIndex.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/mk/index/PropertyIndex.java Tue Apr 24 12:17:27 2012
@@ -119,10 +119,16 @@ public class PropertyIndex implements In
* @param revision the revision
* @return an iterator of the paths (an empty iterator if not found)
*/
+ @Override
public Iterator<String> getPaths(String propertyValue, String revision) {
indexer.updateUntil(revision);
Cursor c = tree.findFirst(propertyValue);
return new Cursor.RangeIterator(c, propertyValue);
}
+ @Override
+ public boolean isUnique() {
+ return tree.isUnique();
+ }
+
}
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/QueryEngine.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/QueryEngine.java?rev=1329667&r1=1329666&r2=1329667&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/QueryEngine.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/QueryEngine.java Tue Apr 24 12:17:27 2012
@@ -28,6 +28,11 @@ import java.util.Map;
public interface QueryEngine {
/**
+ * Initialize the query engine. This includes reading the list of indexes.
+ */
+ void init();
+
+ /**
* Parse the query (check if it's valid) and get the list of bind variable names.
*
* @param statement
@@ -48,4 +53,9 @@ public interface QueryEngine {
*/
Result executeQuery(String statement, String language, Map<String, CoreValue> bindings) throws ParseException;
+ /**
+ * Close the query engine.
+ */
+ void close();
+
}
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/KernelContentRepository.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/KernelContentRepository.java?rev=1329667&r1=1329666&r2=1329667&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/KernelContentRepository.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/KernelContentRepository.java Tue Apr 24 12:17:27 2012
@@ -47,13 +47,18 @@ public class KernelContentRepository imp
private static final String DEFAULT_WORKSPACE_NAME = "default";
private final MicroKernel microKernel;
+ private final CoreValueFactory valueFactory;
+ private final QueryEngine queryEngine;
private final KernelNodeStore nodeStore;
public KernelContentRepository(MicroKernel mk) {
microKernel = mk;
nodeStore = new KernelNodeStore(microKernel);
+ valueFactory = new CoreValueFactoryImpl(microKernel);
+ queryEngine = new QueryEngineImpl(microKernel, valueFactory);
// FIXME: workspace setup must be done elsewhere...
+ queryEngine.init();
NodeState root = nodeStore.getRoot();
NodeState wspNode = root.getChildNode(DEFAULT_WORKSPACE_NAME);
if (wspNode == null) {
@@ -87,9 +92,6 @@ public class KernelContentRepository imp
throw new LoginException("login failed");
}
- CoreValueFactory valueFactory = new CoreValueFactoryImpl(microKernel);
-
- QueryEngine queryEngine = new QueryEngineImpl(microKernel, valueFactory);
// TODO set revision!?
NodeState wspRoot = nodeStore.getRoot().getChildNode(workspaceName);
if (wspRoot == null) {
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/Query.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/Query.java?rev=1329667&r1=1329666&r2=1329667&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/Query.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/Query.java Tue Apr 24 12:17:27 2012
@@ -46,6 +46,8 @@ import org.apache.jackrabbit.oak.query.a
import org.apache.jackrabbit.oak.query.ast.SelectorImpl;
import org.apache.jackrabbit.oak.query.ast.SourceImpl;
import org.apache.jackrabbit.oak.query.ast.UpperCaseImpl;
+import org.apache.jackrabbit.oak.query.index.Filter;
+import org.apache.jackrabbit.oak.query.index.QueryIndex;
/**
* Represents a parsed query. Lifecycle: use the constructor to create a new
@@ -59,6 +61,7 @@ public class Query {
final ArrayList<SelectorImpl> selectors = new ArrayList<SelectorImpl>();
private MicroKernel mk;
+ private QueryEngineImpl queryEngine;
private final OrderingImpl[] orderings;
private ColumnImpl[] columns;
private boolean explain;
@@ -273,7 +276,7 @@ public class Query {
if (explain) {
String plan = source.getPlan();
columns = new ColumnImpl[] { new ColumnImpl("explain", "plan", "plan")};
- ResultRowImpl r = new ResultRowImpl(this, new String[0], new CoreValue[] { valueFactory.createValue(plan) }, null);
+ ResultRowImpl r = new ResultRowImpl(this, new String[0], new CoreValue[] { getValueFactory().createValue(plan) }, null);
it = Arrays.asList(r).iterator();
} else {
it = new RowIterator(revisionId);
@@ -319,7 +322,7 @@ public class Query {
return comp;
}
- private void prepare() {
+ void prepare() {
if (prepared) {
return;
}
@@ -458,4 +461,12 @@ public class Query {
return new ArrayList<String>(bindVariableMap.keySet());
}
+ public void setQueryEngine(QueryEngineImpl queryEngine) {
+ this.queryEngine = queryEngine;
+ }
+
+ public QueryIndex getBestIndex(Filter filter) {
+ return queryEngine.getBestIndex(filter);
+ }
+
}
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryEngineImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryEngineImpl.java?rev=1329667&r1=1329666&r2=1329667&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryEngineImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryEngineImpl.java Tue Apr 24 12:17:27 2012
@@ -17,27 +17,52 @@
package org.apache.jackrabbit.oak.query;
import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.jackrabbit.mk.api.MicroKernel;
+import org.apache.jackrabbit.mk.index.Indexer;
import org.apache.jackrabbit.oak.api.CoreValue;
import org.apache.jackrabbit.oak.api.CoreValueFactory;
import org.apache.jackrabbit.oak.api.QueryEngine;
+import org.apache.jackrabbit.oak.query.index.Filter;
+import org.apache.jackrabbit.oak.query.index.QueryIndex;
+import org.apache.jackrabbit.oak.query.index.TraversingIndex;
+import org.apache.jackrabbit.oak.query.index.QueryIndexProvider.QueryIndexListener;
-public class QueryEngineImpl implements QueryEngine {
+public class QueryEngineImpl implements QueryEngine, QueryIndexListener {
static final String SQL2 = "JCR-SQL2";
private static final String XPATH = "xpath";
+ // TODO discuss where to store index config data
+ private static final String INDEX_CONFIG_ROOT = "/jcr:system/indexes";
+
private final MicroKernel mk;
private final CoreValueFactory vf;
private final SQL2Parser parserSQL2;
+ private final Indexer indexer;
+ private final Map<String, QueryIndex> indexes =
+ Collections.synchronizedMap(new HashMap<String, QueryIndex>());
public QueryEngineImpl(MicroKernel mk, CoreValueFactory valueFactory) {
this.mk = mk;
this.vf = valueFactory;
parserSQL2 = new SQL2Parser(vf);
+ indexer = new Indexer(mk, INDEX_CONFIG_ROOT);
+ }
+
+ public void init() {
+ // TODO the list of index providers should be configurable as well
+ indexer.init();
+ indexer.addListener(this);
+ List<QueryIndex> list = indexer.getQueryIndexes();
+ for (QueryIndex qi : list) {
+ indexes.put(qi.getIndexName(), qi);
+ }
}
/**
@@ -52,7 +77,6 @@ public class QueryEngineImpl implements
public List<String> getBindVariableNames(String statement, String language) throws ParseException {
Query q = parseQuery(statement, language);
return q.getBindVariableNames();
-
}
private Query parseQuery(String statement, String language) throws ParseException {
@@ -78,7 +102,44 @@ public class QueryEngineImpl implements
q.bindValue(e.getKey(), e.getValue());
}
}
+ q.setQueryEngine(this);
+ q.prepare();
return q.executeQuery(mk.getHeadRevision());
}
+ public QueryIndex getBestIndex(Filter filter) {
+ QueryIndex best = null;
+ double bestCost = Double.MAX_VALUE;
+ for (QueryIndex index : getIndexes()) {
+ double cost = index.getCost(filter);
+ if (cost < bestCost) {
+ best = index;
+ }
+ }
+ if (best == null) {
+ best = new TraversingIndex(mk);
+ }
+ return best;
+ }
+
+ private List<QueryIndex> getIndexes() {
+ // create a copy, so the underlying map can be modified
+ return new ArrayList<QueryIndex>(indexes.values());
+ }
+
+ @Override
+ public void added(QueryIndex index) {
+ indexes.put(index.getIndexName(), index);
+ }
+
+ @Override
+ public void removed(QueryIndex index) {
+ indexes.remove(index.getIndexName());
+ }
+
+ @Override
+ public void close() {
+ indexer.removeListener(this);
+ }
+
}
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SelectorImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SelectorImpl.java?rev=1329667&r1=1329666&r2=1329667&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SelectorImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SelectorImpl.java Tue Apr 24 12:17:27 2012
@@ -26,7 +26,6 @@ import org.apache.jackrabbit.oak.query.Q
import org.apache.jackrabbit.oak.query.index.Cursor;
import org.apache.jackrabbit.oak.query.index.Filter;
import org.apache.jackrabbit.oak.query.index.QueryIndex;
-import org.apache.jackrabbit.oak.query.index.TraversingIndex;
public class SelectorImpl extends SourceImpl {
@@ -65,7 +64,7 @@ public class SelectorImpl extends Source
@Override
public void prepare(MicroKernel mk) {
- index = new TraversingIndex(mk);
+ index = query.getBestIndex(createFilter());
}
@Override
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/index/Filter.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/index/Filter.java?rev=1329667&r1=1329666&r2=1329667&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/index/Filter.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/index/Filter.java Tue Apr 24 12:17:27 2012
@@ -305,6 +305,10 @@ public class Filter {
}
public void restrictPath(String addedPath, PathRestriction addedPathRestriction) {
+ if (addedPath == null) {
+ // currently unknown (prepare time)
+ addedPath = "/";
+ }
// calculating the intersection of path restrictions
// this is ugly code, but I don't currently see a radically simpler method
switch (addedPathRestriction) {
Added: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/index/PropertyContentIndex.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/index/PropertyContentIndex.java?rev=1329667&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/index/PropertyContentIndex.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/index/PropertyContentIndex.java Tue Apr 24 12:17:27 2012
@@ -0,0 +1,137 @@
+/*
+ * 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.query.index;
+
+import java.util.Iterator;
+import org.apache.jackrabbit.mk.api.MicroKernel;
+import org.apache.jackrabbit.mk.index.PropertyIndex;
+import org.apache.jackrabbit.mk.simple.NodeImpl;
+import org.apache.jackrabbit.oak.api.CoreValue;
+import org.apache.jackrabbit.oak.query.index.Filter.PropertyRestriction;
+
+/**
+ * An index that stores the index data in a {@code MicroKernel}.
+ */
+public class PropertyContentIndex implements QueryIndex {
+
+ private final MicroKernel mk;
+ private final PropertyIndex index;
+
+ public PropertyContentIndex(MicroKernel mk, PropertyIndex index) {
+ this.mk = mk;
+ this.index = index;
+ }
+
+ @Override
+ public double getCost(Filter filter) {
+ String propertyName = index.getName();
+ PropertyRestriction restriction = filter.getPropertyRestriction(propertyName);
+ if (restriction == null) {
+ return Double.MAX_VALUE;
+ }
+ boolean unique = index.isUnique();
+ if (restriction.first == restriction.last) {
+ return unique ? 2 : 20;
+ }
+ int estimatedMatches = 1000000;
+ if (restriction.first != null) {
+ estimatedMatches /= 10;
+ }
+ if (restriction.last != null) {
+ estimatedMatches /= 10;
+ }
+ if (unique) {
+ estimatedMatches /= 100;
+ }
+ return estimatedMatches;
+ }
+
+ @Override
+ public String getPlan(Filter filter) {
+ String propertyName = index.getName();
+ PropertyRestriction restriction = filter.getPropertyRestriction(propertyName);
+
+ return "propertyIndex \"" + restriction.propertyName + " " + restriction.toString() + '"';
+ }
+
+ @Override
+ public Cursor query(Filter filter, String revisionId) {
+ String propertyName = index.getName();
+ PropertyRestriction restriction = filter.getPropertyRestriction(propertyName);
+ if (restriction == null) {
+ throw new IllegalArgumentException("No restriction for " + propertyName);
+ }
+ CoreValue first = restriction.first;
+ String f = first == null ? null : first.toString();
+ Iterator<String> it = index.getPaths(f, revisionId);
+ return new ContentCursor(mk, revisionId, it);
+ }
+
+
+ @Override
+ public String getIndexName() {
+ return index.getName();
+ }
+
+ /**
+ * The cursor to for this index.
+ */
+ static class ContentCursor implements Cursor {
+
+ private final MicroKernel mk;
+ private final String revisionId;
+ private final Iterator<String> it;
+
+ private String currentPath;
+ private NodeImpl currentNode;
+
+ public ContentCursor(MicroKernel mk, String revisionId, Iterator<String> it) {
+ this.mk = mk;
+ this.revisionId = revisionId;
+ this.it = it;
+ }
+
+ @Override
+ public NodeImpl currentNode() {
+ // TODO same code as in TraversingCursor
+ if (currentNode == null) {
+ if (currentPath == null) {
+ return null;
+ }
+ currentNode = NodeImpl.parse(mk.getNodes(currentPath, revisionId));
+ currentNode.setPath(currentPath);
+ }
+ return currentNode;
+ }
+
+ @Override
+ public String currentPath() {
+ return currentPath;
+ }
+
+ @Override
+ public boolean next() {
+ if (it.hasNext()) {
+ currentPath = it.next();
+ }
+ return false;
+ }
+ }
+
+}
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/index/QueryIndex.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/index/QueryIndex.java?rev=1329667&r1=1329666&r2=1329667&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/index/QueryIndex.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/index/QueryIndex.java Tue Apr 24 12:17:27 2012
@@ -51,4 +51,11 @@ public interface QueryIndex {
*/
String getPlan(Filter filter);
+ /**
+ * Get the unique index name.
+ *
+ * @return the index name
+ */
+ String getIndexName();
+
}
Added: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/index/QueryIndexProvider.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/index/QueryIndexProvider.java?rev=1329667&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/index/QueryIndexProvider.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/index/QueryIndexProvider.java Tue Apr 24 12:17:27 2012
@@ -0,0 +1,78 @@
+/*
+ * 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.query.index;
+
+import java.util.List;
+
+/**
+ * A mechanism to index data. Indexes might be added or removed at runtime,
+ * possibly by changing content in the repository. The provider knows about
+ * indexes, and informs the query engine about indexes that where added or
+ * removed at runtime.
+ */
+public interface QueryIndexProvider {
+
+ /**
+ * Initialize the instance.
+ */
+ void init();
+
+ /**
+ * Get the currently configured indexes.
+ *
+ * @return the list of indexes
+ */
+ List<QueryIndex> getQueryIndexes();
+
+ /**
+ * Add a listener that is notified about added and removed indexes.
+ *
+ * @param listener the listener
+ */
+ void addListener(QueryIndexListener listener);
+
+ /**
+ * Remove a listener.
+ *
+ * @param listener the listener
+ */
+ void removeListener(QueryIndexListener listener);
+
+ /**
+ * A query index listener
+ */
+ public interface QueryIndexListener {
+
+ /**
+ * The given index was added.
+ *
+ * @param index the index
+ */
+ void added(QueryIndex index);
+
+ /**
+ * The given index was removed.
+ *
+ * @param index the index
+ */
+ void removed(QueryIndex index);
+
+ }
+
+}
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/index/TraversingIndex.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/index/TraversingIndex.java?rev=1329667&r1=1329666&r2=1329667&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/index/TraversingIndex.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/index/TraversingIndex.java Tue Apr 24 12:17:27 2012
@@ -63,4 +63,9 @@ public class TraversingIndex implements
return "traverse \"" + p + r + '"';
}
+ @Override
+ public String getIndexName() {
+ return "traverse";
+ }
+
}
Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/mk/index/IndexTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/mk/index/IndexTest.java?rev=1329667&r1=1329666&r2=1329667&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/mk/index/IndexTest.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/mk/index/IndexTest.java Tue Apr 24 12:17:27 2012
@@ -34,6 +34,7 @@ public class IndexTest {
@Test
public void createIndexAfterAddingData() {
Indexer indexer = new Indexer(mk);
+ indexer.init();
PropertyIndex indexOld = indexer.createPropertyIndex("x", false);
mk.commit("/", "+ \"test\": { \"test2\": { \"id\": 1 }, \"id\": 1 }", mk.getHeadRevision(), "");
mk.commit("/", "+ \"test3\": { \"test2\": { \"id\": 2 }, \"id\": 2 }", mk.getHeadRevision(), "");
@@ -50,6 +51,7 @@ public class IndexTest {
@Test
public void nonUnique() {
Indexer indexer = new Indexer(mk);
+ indexer.init();
PropertyIndex index = indexer.createPropertyIndex("id", false);
mk.commit("/", "+ \"test\": { \"test2\": { \"id\": 1 }, \"id\": 1 }", mk.getHeadRevision(), "");
mk.commit("/", "+ \"test3\": { \"test2\": { \"id\": 2 }, \"id\": 2 }", mk.getHeadRevision(), "");
@@ -64,6 +66,7 @@ public class IndexTest {
@Test
public void nestedAddNode() {
Indexer indexer = new Indexer(mk);
+ indexer.init();
PropertyIndex index = indexer.createPropertyIndex("id", true);
mk.commit("/", "+ \"test\": { \"test2\": { \"id\": 2 }, \"id\": 1 }", mk.getHeadRevision(), "");
@@ -74,6 +77,7 @@ public class IndexTest {
@Test
public void move() {
Indexer indexer = new Indexer(mk);
+ indexer.init();
PropertyIndex index = indexer.createPropertyIndex("id", true);
mk.commit("/", "+ \"test\": { \"test2\": { \"id\": 2 }, \"id\": 1 }", mk.getHeadRevision(), "");
@@ -88,6 +92,7 @@ public class IndexTest {
@Test
public void copy() {
Indexer indexer = new Indexer(mk);
+ indexer.init();
PropertyIndex index = indexer.createPropertyIndex("id", false);
mk.commit("/", "+ \"test\": { \"test2\": { \"id\": 2 }, \"id\": 1 }", mk.getHeadRevision(), "");
@@ -112,6 +117,7 @@ public class IndexTest {
@Test
public void ascending() {
Indexer indexer = new Indexer(mk);
+ indexer.init();
BTree tree = new BTree(indexer, "test", true);
tree.setMinSize(2);
print(mk, tree);
@@ -154,6 +160,7 @@ public class IndexTest {
private void duplicateKey(boolean unique) {
Indexer indexer = new Indexer(mk);
+ indexer.init();
BTree tree = new BTree(indexer, "test", unique);
tree.setMinSize(2);
@@ -197,6 +204,7 @@ public class IndexTest {
@Test
public void random() {
Indexer indexer = new Indexer(mk);
+ indexer.init();
BTree tree = new BTree(indexer, "test", true);
tree.setMinSize(2);
Random r = new Random(1);
Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/mk/index/PrefixIndexTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/mk/index/PrefixIndexTest.java?rev=1329667&r1=1329666&r2=1329667&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/mk/index/PrefixIndexTest.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/mk/index/PrefixIndexTest.java Tue Apr 24 12:17:27 2012
@@ -31,6 +31,7 @@ public class PrefixIndexTest {
public void test() {
MicroKernel mk = new MicroKernelImpl();
Indexer indexer = new Indexer(mk, "index");
+ indexer.init();
PrefixIndex index = indexer.createPrefixIndex("d:");
String head = mk.getHeadRevision();
Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/mk/index/PropertyIndexTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/mk/index/PropertyIndexTest.java?rev=1329667&r1=1329666&r2=1329667&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/mk/index/PropertyIndexTest.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/mk/index/PropertyIndexTest.java Tue Apr 24 12:17:27 2012
@@ -30,6 +30,7 @@ public class PropertyIndexTest {
public void test() {
MicroKernel mk = new MicroKernelImpl();
Indexer indexer = new Indexer(mk, "index");
+ indexer.init();
PropertyIndex index = indexer.createPropertyIndex("id", true);
String head = mk.getHeadRevision();
@@ -61,6 +62,7 @@ public class PropertyIndexTest {
// Recreate the indexer
indexer = new Indexer(mk);
+ indexer.init();
index = indexer.createPropertyIndex("id", true);
head = mk.getHeadRevision();
Assert.assertEquals("/test/test", index.getPath("3", head));
Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/AbstractQueryTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/AbstractQueryTest.java?rev=1329667&r1=1329666&r2=1329667&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/AbstractQueryTest.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/AbstractQueryTest.java Tue Apr 24 12:17:27 2012
@@ -20,19 +20,12 @@ import org.apache.jackrabbit.mk.api.Micr
import org.apache.jackrabbit.mk.core.MicroKernelImpl;
import org.apache.jackrabbit.oak.api.CoreValueFactory;
import org.apache.jackrabbit.oak.core.CoreValueFactoryImpl;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
/**
* AbstractQueryTest...
*/
public abstract class AbstractQueryTest {
- /**
- * logger instance
- */
- private static final Logger log = LoggerFactory.getLogger(AbstractQueryTest.class);
-
// TODO improve: use ContentRepository here instead of creating mk instance.
protected final MicroKernel mk = new MicroKernelImpl();
protected final CoreValueFactory vf = new CoreValueFactoryImpl(mk);
Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/QueryTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/QueryTest.java?rev=1329667&r1=1329666&r2=1329667&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/QueryTest.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/QueryTest.java Tue Apr 24 12:17:27 2012
@@ -13,11 +13,8 @@
*/
package org.apache.jackrabbit.oak.query;
-import org.apache.jackrabbit.oak.api.CoreValue;
-import org.apache.jackrabbit.oak.api.Result;
-import org.apache.jackrabbit.oak.api.ResultRow;
-import org.junit.Test;
-
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
@@ -30,9 +27,11 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
+import org.apache.jackrabbit.oak.api.CoreValue;
+import org.apache.jackrabbit.oak.api.Result;
+import org.apache.jackrabbit.oak.api.ResultRow;
+import org.junit.Before;
+import org.junit.Test;
/**
* Test the query feature.
@@ -41,6 +40,11 @@ public class QueryTest extends AbstractQ
private QueryEngineImpl qe = new QueryEngineImpl(mk, vf);
+ @Before
+ public void setup() {
+ qe.init();
+ }
+
@Test
public void script() throws Exception {
test("queryTest.txt");
Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/index/FilterTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/index/FilterTest.java?rev=1329667&r1=1329666&r2=1329667&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/index/FilterTest.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/index/FilterTest.java Tue Apr 24 12:17:27 2012
@@ -18,19 +18,17 @@
*/
package org.apache.jackrabbit.oak.query.index;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import java.util.ArrayList;
+import java.util.Random;
import org.apache.jackrabbit.oak.api.CoreValue;
import org.apache.jackrabbit.oak.query.AbstractQueryTest;
import org.apache.jackrabbit.oak.query.ast.Operator;
import org.apache.jackrabbit.oak.query.index.Filter.PathRestriction;
import org.junit.Test;
-import java.util.ArrayList;
-import java.util.Random;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
/**
* Tests the Filter class.
*/
Modified: jackrabbit/oak/trunk/oak-core/src/test/resources/org/apache/jackrabbit/oak/query/queryTest.txt
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/resources/org/apache/jackrabbit/oak/query/queryTest.txt?rev=1329667&r1=1329666&r2=1329667&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/resources/org/apache/jackrabbit/oak/query/queryTest.txt (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/resources/org/apache/jackrabbit/oak/query/queryTest.txt Tue Apr 24 12:17:27 2012
@@ -32,6 +32,8 @@ select * from [nt:base] as b where local
select * from [nt:base] as x where isdescendantnode(x, '/')
/
+/jcr:system
+/jcr:system/indexes
/test
/test/jcr:resource
/test/resource
@@ -51,6 +53,7 @@ select * from [nt:base] as p where p.[jc
select * from [nt:base] as p inner join [nt:base] as p2 on ischildnode(p2, p) where p.[jcr:path] = '/'
/, /children
+/, /jcr:system
/, /parents
select * from [nt:base] as p inner join [nt:base] as p2 on isdescendantnode(p2, p) where p.[jcr:path] = '/parents'
@@ -107,6 +110,8 @@ nt:base AS p /* traverse "//*" */ INNER
select * from [nt:base]
/
+/jcr:system
+/jcr:system/indexes
/test
/test/hello
/test/world
@@ -124,11 +129,15 @@ select * from [nt:base] where id = '1' o
select * from [nt:base] where not (id = '1' or x = '2')
/
+/jcr:system
+/jcr:system/indexes
/test
/test/hello
select * from [nt:base] where x is null
/
+/jcr:system
+/jcr:system/indexes
/test
- "test"
@@ -147,6 +156,8 @@ Hallo
hello
World!
null
+null
+null
select * from [nt:base] where length(name) = 5
/test