Author: chetanm
Date: Wed Oct 8 10:10:16 2014
New Revision: 1630056
URL: http://svn.apache.org/r1630056
Log:
OAK-2122 - Make LuceneIndex implement AdvanceQueryIndex
Implemented AdvanceFulltextQueryIndex. The cost calculation is currently done
in a naive way where it sets the number of entries to 0 and then provide a cost
per execution thus effective cost is same as the one returned earlier.
Also moved getRelativePaths with no change in its logic
Modified:
jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndex.java
jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LowCostLuceneIndexProvider.java
jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexTest.java
Modified:
jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndex.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndex.java?rev=1630056&r1=1630055&r2=1630056&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndex.java
(original)
+++
jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndex.java
Wed Oct 8 10:10:16 2014
@@ -33,6 +33,7 @@ import static org.apache.jackrabbit.oak.
import static
org.apache.jackrabbit.oak.plugins.index.lucene.TermFactory.newPathTerm;
import static
org.apache.jackrabbit.oak.plugins.index.lucene.util.LuceneIndexHelper.skipTokenization;
import static org.apache.jackrabbit.oak.query.QueryImpl.JCR_PATH;
+import static
org.apache.jackrabbit.oak.spi.query.QueryIndex.AdvanceFulltextQueryIndex;
import static org.apache.lucene.search.BooleanClause.Occur.MUST;
import static org.apache.lucene.search.BooleanClause.Occur.MUST_NOT;
import static org.apache.lucene.search.BooleanClause.Occur.SHOULD;
@@ -72,7 +73,6 @@ import org.apache.jackrabbit.oak.spi.que
import org.apache.jackrabbit.oak.spi.query.IndexRow;
import org.apache.jackrabbit.oak.spi.query.PropertyValues;
import org.apache.jackrabbit.oak.spi.query.QueryIndex;
-import org.apache.jackrabbit.oak.spi.query.QueryIndex.FulltextQueryIndex;
import org.apache.jackrabbit.oak.spi.state.NodeState;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.TokenStream;
@@ -145,7 +145,7 @@ import org.slf4j.LoggerFactory;
* @see QueryIndex
*
*/
-public class LuceneIndex implements FulltextQueryIndex {
+public class LuceneIndex implements AdvanceFulltextQueryIndex {
private static final Logger LOG = LoggerFactory
.getLogger(LuceneIndex.class);
@@ -178,17 +178,17 @@ public class LuceneIndex implements Full
}
@Override
- public double getCost(Filter filter, NodeState root) {
+ public List<IndexPlan> getPlans(Filter filter, List<OrderEntry> sortOrder,
NodeState rootState) {
FullTextExpression ft = filter.getFullTextConstraint();
if (ft == null) {
// no full-text condition: don't use this index,
// as there might be a better one
- return Double.POSITIVE_INFINITY;
+ return Collections.emptyList();
}
IndexNode index = tracker.acquireIndexNode("/");
if (index == null) { // unusable index
- return Double.POSITIVE_INFINITY;
+ return Collections.emptyList();
}
try {
Set<String> relPaths = getRelativePaths(ft);
@@ -196,72 +196,42 @@ public class LuceneIndex implements Full
LOG.warn("More than one relative parent for query " +
filter.getQueryStatement());
// there are multiple "parents", as in
// "contains(a/x, 'hello') and contains(b/x, 'world')"
- return new MultiLuceneIndex(filter, root, relPaths).getCost();
+ return Collections.emptyList();
}
String parent = relPaths.iterator().next();
- if (parent.isEmpty()) {
- // no relative properties
- return 10;
- }
- // all relative properties have the same "parent", as in
- // "contains(a/x, 'hello') and contains(a/y, 'world')" or
- // "contains(a/x, 'hello') or contains(a/*, 'world')"
- // TODO: proper cost calculation
- // we assume this will cause more read operations,
- // as we need to read the node and then the parent
- return 15;
+
+ // no relative properties
+ double cost = 10;
+ if (!parent.isEmpty()) {
+ // all relative properties have the same "parent", as in
+ // "contains(a/x, 'hello') and contains(a/y, 'world')" or
+ // "contains(a/x, 'hello') or contains(a/*, 'world')"
+ // TODO: proper cost calculation
+ // we assume this will cause more read operations,
+ // as we need to read the node and then the parent
+ cost = 15;
+ }
+ return Collections.singletonList(planBuilder(filter)
+ .setCostPerExecution(cost)
+ .build());
} finally {
index.release();
}
}
- /**
- * Get the set of relative paths of a full-text condition. For example, for
- * the condition "contains(a/b, 'hello') and contains(c/d, 'world'), the
set
- * { "a", "c" } is returned. If there are no relative properties, then one
- * entry is returned (the empty string). If there is no expression, then an
- * empty set is returned.
- *
- * @param ft the full-text expression
- * @return the set of relative paths (possibly empty)
- */
- private static Set<String> getRelativePaths(FullTextExpression ft) {
- if (ft == null) {
- // there might be no full-text constraint when using the
- // LowCostLuceneIndexProvider which is used for testing
- // TODO if the LowCostLuceneIndexProvider is removed, we should do
- // the following instead:
-
- // throw new
- // IllegalStateException("Lucene index is used even when no
full-text conditions are used for filter "
- // + filter);
-
- return Collections.emptySet();
- }
- final HashSet<String> relPaths = new HashSet<String>();
- ft.accept(new FullTextVisitor.FullTextVisitorBase() {
-
- @Override
- public boolean visit(FullTextTerm term) {
- String p = term.getPropertyName();
- if (p == null) {
- relPaths.add("");
- } else if (p.startsWith("../") || p.startsWith("./")) {
- throw new IllegalArgumentException("Relative parent is not
supported:" + p);
- } else if (getDepth(p) > 1) {
- String parent = getParentPath(p);
- relPaths.add(parent);
- } else {
- relPaths.add("");
- }
- return true;
- }
- });
- return relPaths;
+ @Override
+ public double getCost(Filter filter, NodeState root) {
+ throw new UnsupportedOperationException("Not supported as implementing
AdvancedQueryIndex");
}
@Override
public String getPlan(Filter filter, NodeState root) {
+ throw new UnsupportedOperationException("Not supported as implementing
AdvancedQueryIndex");
+ }
+
+ @Override
+ public String getPlanDescription(IndexPlan plan, NodeState root) {
+ Filter filter = plan.getFilter();
IndexNode index = tracker.acquireIndexNode("/");
checkState(index != null, "The Lucene index is not available");
try {
@@ -274,11 +244,11 @@ public class LuceneIndex implements Full
// we only restrict non-full-text conditions if there is
// no relative property in the full-text constraint
boolean nonFullTextConstraints = parent.isEmpty();
- String plan = getQuery(filter, null, nonFullTextConstraints,
analyzer, index.getDefinition()) + " ft:(" + ft + ")";
+ String planDesc = getQuery(filter, null, nonFullTextConstraints,
analyzer, index.getDefinition()) + " ft:(" + ft + ")";
if (!parent.isEmpty()) {
- plan += " parent:" + parent;
+ planDesc += " parent:" + parent;
}
- return plan;
+ return planDesc;
} finally {
index.release();
}
@@ -286,10 +256,16 @@ public class LuceneIndex implements Full
@Override
public Cursor query(final Filter filter, final NodeState root) {
+ throw new UnsupportedOperationException("Not supported as implementing
AdvancedQueryIndex");
+ }
+
+ @Override
+ public Cursor query(IndexPlan plan, NodeState rootState) {
+ final Filter filter = plan.getFilter();
FullTextExpression ft = filter.getFullTextConstraint();
Set<String> relPaths = getRelativePaths(ft);
if (relPaths.size() > 1) {
- return new MultiLuceneIndex(filter, root, relPaths).query();
+ return new MultiLuceneIndex(filter, rootState, relPaths).query();
}
final String parent = relPaths.size() == 0 ? "" :
relPaths.iterator().next();
@@ -391,6 +367,63 @@ public class LuceneIndex implements Full
return new LucenePathCursor(itr, settings);
}
+ protected static IndexPlan.Builder planBuilder(Filter filter){
+ return new IndexPlan.Builder()
+ .setCostPerExecution(0) // we're local. Low-cost
+ .setCostPerEntry(1)
+ .setFilter(filter)
+ .setFulltextIndex(true)
+ .setEstimatedEntryCount(0) //TODO Fake it to provide constant
cost for now
+ .setIncludesNodeData(false) // we should not include node data
+ .setDelayed(true); //Lucene is always async
+ }
+
+ /**
+ * Get the set of relative paths of a full-text condition. For example, for
+ * the condition "contains(a/b, 'hello') and contains(c/d, 'world'), the
set
+ * { "a", "c" } is returned. If there are no relative properties, then one
+ * entry is returned (the empty string). If there is no expression, then an
+ * empty set is returned.
+ *
+ * @param ft the full-text expression
+ * @return the set of relative paths (possibly empty)
+ */
+ private static Set<String> getRelativePaths(FullTextExpression ft) {
+ if (ft == null) {
+ // there might be no full-text constraint when using the
+ // LowCostLuceneIndexProvider which is used for testing
+ // TODO if the LowCostLuceneIndexProvider is removed, we should do
+ // the following instead:
+
+ // throw new
+ // IllegalStateException("Lucene index is used even when no
full-text conditions are used for filter "
+ // + filter);
+
+ return Collections.emptySet();
+ }
+ final HashSet<String> relPaths = new HashSet<String>();
+ ft.accept(new FullTextVisitor.FullTextVisitorBase() {
+
+ @Override
+ public boolean visit(FullTextTerm term) {
+ String p = term.getPropertyName();
+ if (p == null) {
+ relPaths.add("");
+ } else if (p.startsWith("../") || p.startsWith("./")) {
+ throw new IllegalArgumentException("Relative parent is not
supported:" + p);
+ } else if (getDepth(p) > 1) {
+ String parent = getParentPath(p);
+ relPaths.add(parent);
+ } else {
+ relPaths.add("");
+ }
+ return true;
+ }
+ });
+ return relPaths;
+ }
+
+
/**
* Get the Lucene query for the given filter.
*
@@ -894,7 +927,7 @@ public class LuceneIndex implements Full
public NodeAggregator getNodeAggregator() {
return aggregator;
}
-
+
static class LuceneResultRow {
final String path;
final double score;
Modified:
jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LowCostLuceneIndexProvider.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LowCostLuceneIndexProvider.java?rev=1630056&r1=1630055&r2=1630056&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LowCostLuceneIndexProvider.java
(original)
+++
jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LowCostLuceneIndexProvider.java
Wed Oct 8 10:10:16 2014
@@ -16,6 +16,9 @@
*/
package org.apache.jackrabbit.oak.plugins.index.lucene;
+import java.util.Collections;
+import java.util.List;
+
import org.apache.jackrabbit.oak.plugins.index.aggregate.NodeAggregator;
import org.apache.jackrabbit.oak.spi.query.Filter;
import org.apache.jackrabbit.oak.spi.state.NodeState;
@@ -40,8 +43,10 @@ public class LowCostLuceneIndexProvider
}
@Override
- public double getCost(Filter filter, NodeState root) {
- return 1e-3;
+ public List<IndexPlan> getPlans(Filter filter, List<OrderEntry>
sortOrder, NodeState rootState) {
+ return Collections.singletonList(planBuilder(filter)
+ .setCostPerExecution(1e-3)
+ .build());
}
}
}
Modified:
jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexTest.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexTest.java?rev=1630056&r1=1630055&r2=1630056&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexTest.java
(original)
+++
jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexTest.java
Wed Oct 8 10:10:16 2014
@@ -37,6 +37,8 @@ import static org.apache.jackrabbit.oak.
import static
org.apache.jackrabbit.oak.plugins.index.lucene.util.LuceneIndexHelper.newLuceneIndexDefinition;
import static
org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants.JCR_NODE_TYPES;
import static
org.apache.jackrabbit.oak.plugins.nodetype.write.InitialContent.INITIAL_CONTENT;
+import static
org.apache.jackrabbit.oak.spi.query.QueryIndex.AdvancedQueryIndex;
+import static org.apache.jackrabbit.oak.spi.query.QueryIndex.IndexPlan;
import com.google.common.base.Function;
import org.apache.jackrabbit.oak.api.Type;
@@ -55,7 +57,6 @@ import org.apache.jackrabbit.oak.spi.que
import org.apache.jackrabbit.oak.spi.query.Filter;
import org.apache.jackrabbit.oak.spi.query.IndexRow;
import org.apache.jackrabbit.oak.spi.query.PropertyValues;
-import org.apache.jackrabbit.oak.spi.query.QueryIndex;
import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
import org.apache.jackrabbit.oak.spi.state.NodeState;
import org.apache.jackrabbit.oak.spi.state.NodeStore;
@@ -91,12 +92,12 @@ public class LuceneIndexTest {
IndexTracker tracker = new IndexTracker();
tracker.update(indexed);
- QueryIndex queryIndex = new LuceneIndex(tracker, analyzer, null);
+ AdvancedQueryIndex queryIndex = new LuceneIndex(tracker, analyzer,
null);
FilterImpl filter = createFilter(NT_BASE);
filter.restrictPath("/", Filter.PathRestriction.EXACT);
filter.restrictProperty("foo", Operator.EQUAL,
PropertyValues.newString("bar"));
- Cursor cursor = queryIndex.query(filter, indexed);
+ Cursor cursor = queryIndex.query(createPlan(filter), indexed);
assertTrue(cursor.hasNext());
assertEquals("/", cursor.next().getPath());
assertFalse(cursor.hasNext());
@@ -121,11 +122,11 @@ public class LuceneIndexTest {
IndexTracker tracker = new IndexTracker();
tracker.update(indexed);
- QueryIndex queryIndex = new LuceneIndex(tracker, analyzer, null);
+ AdvancedQueryIndex queryIndex = new LuceneIndex(tracker, analyzer,
null);
FilterImpl filter = createFilter(NT_BASE);
filter.restrictProperty("foo", Operator.EQUAL,
PropertyValues.newString("bar"));
- Cursor cursor = queryIndex.query(filter, indexed);
+ Cursor cursor = queryIndex.query(createPlan(filter), indexed);
List<String> paths = copyOf(transform(cursor, new Function<IndexRow,
String>() {
public String apply(IndexRow input) {
@@ -154,12 +155,12 @@ public class LuceneIndexTest {
IndexTracker tracker = new IndexTracker();
tracker.update(indexed);
- QueryIndex queryIndex = new LuceneIndex(tracker, analyzer, null);
+ AdvancedQueryIndex queryIndex = new LuceneIndex(tracker, analyzer,
null);
FilterImpl filter = createFilter(NT_BASE);
// filter.restrictPath("/", Filter.PathRestriction.EXACT);
filter.restrictProperty("foo", Operator.EQUAL,
PropertyValues.newString("bar"));
- Cursor cursor = queryIndex.query(filter, indexed);
+ Cursor cursor = queryIndex.query(createPlan(filter), indexed);
assertTrue(cursor.hasNext());
assertEquals("/a/b/c", cursor.next().getPath());
@@ -188,12 +189,12 @@ public class LuceneIndexTest {
IndexTracker tracker = new IndexTracker();
tracker.update(indexed);
- QueryIndex queryIndex = new LuceneIndex(tracker, analyzer, null);
+ AdvancedQueryIndex queryIndex = new LuceneIndex(tracker, analyzer,
null);
FilterImpl filter = createFilter(NT_BASE);
// filter.restrictPath("/", Filter.PathRestriction.EXACT);
filter.restrictProperty("foo", Operator.EQUAL,
PropertyValues.newString("bar"));
- Cursor cursor = queryIndex.query(filter, indexed);
+ Cursor cursor = queryIndex.query(createPlan(filter), indexed);
assertTrue(cursor.hasNext());
assertEquals("/a", cursor.next().getPath());
@@ -271,12 +272,12 @@ public class LuceneIndexTest {
}
private void assertQuery(IndexTracker tracker, NodeState indexed, String
key, String value){
- QueryIndex queryIndex = new LuceneIndex(tracker, analyzer, null);
+ AdvancedQueryIndex queryIndex = new LuceneIndex(tracker, analyzer,
null);
FilterImpl filter = createFilter(NT_BASE);
filter.restrictPath("/", Filter.PathRestriction.EXACT);
filter.restrictProperty(key, Operator.EQUAL,
PropertyValues.newString(value));
- Cursor cursor = queryIndex.query(filter, indexed);
+ Cursor cursor = queryIndex.query(createPlan(filter), indexed);
assertTrue(cursor.hasNext());
assertEquals("/", cursor.next().getPath());
assertFalse(cursor.hasNext());
@@ -287,4 +288,8 @@ public class LuceneIndexTest {
return dir.getAbsolutePath();
}
+ private IndexPlan createPlan(Filter filter){
+ return new IndexPlan.Builder().setFilter(filter).build();
+ }
+
}