Index: oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/IndexDefinition.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/IndexDefinition.java (date 1414158339000) +++ oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/IndexDefinition.java (revision ) @@ -40,6 +40,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import static org.apache.jackrabbit.oak.plugins.index.IndexConstants.ENTRY_COUNT_PROPERTY_NAME; import static org.apache.jackrabbit.oak.plugins.index.lucene.LuceneIndexConstants.BLOB_SIZE; import static org.apache.jackrabbit.oak.plugins.index.lucene.LuceneIndexConstants.EXCLUDE_PROPERTY_NAMES; import static org.apache.jackrabbit.oak.plugins.index.lucene.LuceneIndexConstants.EXPERIMENTAL_STORAGE; @@ -57,6 +58,11 @@ */ static final int DEFAULT_BLOB_SIZE = OakDirectory.DEFAULT_BLOB_SIZE - 300; + /** + * Default entry count to keep estimated entry count low. + */ + static final long DEFAULT_ENTRY_COUNT = 1000; + private final int propertyTypes; private final Set excludes; @@ -79,6 +85,12 @@ private final Codec codec; + /** + * Defines the maximum estimated entry count configured. + * Defaults to {#DEFAULT_ENTRY_COUNT} + */ + private final long entryCount; + public IndexDefinition(NodeBuilder defn) { this.definition = defn; PropertyState pst = defn.getProperty(INCLUDE_PROPERTY_TYPES); @@ -118,7 +130,13 @@ this.funcName = functionName != null ? "native*" + functionName : null; this.codec = createCodec(); + + if (defn.hasProperty(ENTRY_COUNT_PROPERTY_NAME)) { + this.entryCount = defn.getProperty(ENTRY_COUNT_PROPERTY_NAME).getValue(Type.LONG); + } else { + this.entryCount = DEFAULT_ENTRY_COUNT; - } + } + } boolean includeProperty(String name) { if(!includes.isEmpty()){ @@ -193,6 +211,10 @@ public Codec getCodec() { return codec; + } + + public long getEntryCount() { + return entryCount; } //~------------------------------------------< Internal > Index: oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/IndexPlanner.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/IndexPlanner.java (date 1414158339000) +++ oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/IndexPlanner.java (revision ) @@ -112,7 +112,7 @@ .setSortOrder(createSortOrder()) .setDelayed(true) //Lucene is always async .setAttribute(LuceneIndex.ATTR_INDEX_PATH, indexPath) - .setEstimatedEntryCount(getReader().numDocs()); + .setEstimatedEntryCount(Math.min(defn.getEntryCount(), getReader().numDocs())); } private String getPathPrefix() { Index: oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LucenePropertyIndex.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LucenePropertyIndex.java (date 1414158339000) +++ oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LucenePropertyIndex.java (revision ) @@ -888,7 +888,10 @@ bq.add(new TermQuery(new Term(JCR_MIXINTYPES, type)), SHOULD); } } + + if (bq.clauses().size() != 0) { - qs.add(bq); + qs.add(bq); + } } static Query getFullTextQuery(FullTextExpression ft, final Analyzer analyzer, final IndexReader reader) { Index: oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LucenePropertyIndexTest.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LucenePropertyIndexTest.java (date 1414158339000) +++ oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LucenePropertyIndexTest.java (revision ) @@ -36,7 +36,10 @@ import org.apache.jackrabbit.oak.api.ContentRepository; import org.apache.jackrabbit.oak.api.Tree; import org.apache.jackrabbit.oak.api.Type; +import org.apache.jackrabbit.oak.plugins.index.IndexConstants; import org.apache.jackrabbit.oak.plugins.index.lucene.util.LuceneInitializerHelper; +import org.apache.jackrabbit.oak.plugins.index.nodetype.NodeTypeIndexProvider; +import org.apache.jackrabbit.oak.plugins.index.property.PropertyIndexEditorProvider; import org.apache.jackrabbit.oak.plugins.memory.PropertyStates; import org.apache.jackrabbit.oak.plugins.nodetype.write.InitialContent; import org.apache.jackrabbit.oak.query.AbstractQueryTest; @@ -85,6 +88,8 @@ .with((QueryIndexProvider) provider) .with((Observer) provider) .with(new LuceneIndexEditorProvider()) + .with(new PropertyIndexEditorProvider()) + .with(new NodeTypeIndexProvider()) .createContentRepository(); } @@ -108,6 +113,35 @@ assertQuery(propaQuery, asList("/test/a", "/test/b")); assertQuery("select [jcr:path] from [nt:base] where [propa] = 'foo2'", asList("/test/c")); assertQuery("select [jcr:path] from [nt:base] where [propc] = 'foo'", asList("/test/d")); + } + + @Test + public void indexSelectionVsNodeType() throws Exception { + Tree luceneIndex = createIndex("test1", of("propa")); + luceneIndex.setProperty(IndexConstants.ENTRY_COUNT_PROPERTY_NAME, 5L, Type.LONG); + + // Decrease cost of node type index + Tree nodeTypeIndex = root.getTree("/").getChild("oak:index").getChild("nodetype"); + nodeTypeIndex.setProperty(IndexConstants.ENTRY_COUNT_PROPERTY_NAME, 50L, Type.LONG); + nodeTypeIndex.setProperty(IndexConstants.KEY_COUNT_PROPERTY_NAME, 10L, Type.LONG); + + Tree test = root.getTree("/").addChild("test"); + test.setProperty("jcr:primaryType", "nt:unstructured", Type.NAME); + + List paths = Lists.newArrayList(); + for (int idx = 0; idx < 15; idx++) { + Tree a = test.addChild("n"+idx); + a.setProperty("jcr:primaryType", "nt:unstructured", Type.NAME); + a.setProperty("propa", "foo"); + paths.add("/test/n" + idx); + } + root.commit(); + + String propaQuery = "select [jcr:path] from [nt:unstructured] where [propa] = 'foo'"; + String explain = explain(propaQuery); + assertThat(explain(propaQuery), containsString("lucene:test1")); + + assertQuery(propaQuery, paths); } @Test