Author: chetanm Date: Mon Oct 16 10:22:51 2017 New Revision: 1812274 URL: http://svn.apache.org/viewvc?rev=1812274&view=rev Log: OAK-6831 - Nodetype index support in Lucene Index
-- Support for 'nodeTypeIndex' property at index definition node -- Support for 'sync' indexRules to indicate that nodeTypeIndex for that node is to be indexed in 'sync' mode Modified: jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/IndexDefinition.java jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexConstants.java jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/util/IndexDefinitionBuilder.java jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/IndexDefinitionTest.java jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/IndexPlannerTest.java jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LucenePropertyIndexTest.java jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/util/IndexDefinitionBuilderTest.java Modified: jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/IndexDefinition.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/IndexDefinition.java?rev=1812274&r1=1812273&r2=1812274&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/IndexDefinition.java (original) +++ jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/IndexDefinition.java Mon Oct 16 10:22:51 2017 @@ -260,6 +260,8 @@ public final class IndexDefinition imple private final boolean nrtIndexMode; private final boolean syncIndexMode; + private final boolean nodeTypeIndex; + @Nullable private final String uid; @@ -339,6 +341,7 @@ public final class IndexDefinition imple this.indexPath = checkNotNull(indexPath); this.indexName = indexPath; this.indexTags = getOptionalStrings(defn, IndexConstants.INDEX_TAGS); + this.nodeTypeIndex = getOptionalValue(defn, LuceneIndexConstants.PROP_INDEX_NODE_TYPE, false); this.blobSize = getOptionalValue(defn, BLOB_SIZE, DEFAULT_BLOB_SIZE); this.testMode = getOptionalValue(defn, LuceneIndexConstants.TEST_MODE, false); @@ -562,6 +565,10 @@ public final class IndexDefinition imple return syncPropertyIndexes; } + public boolean isPureNodeTypeIndex() { + return nodeTypeIndex; + } + /** * Check if the index definition is fresh of some index has happened * @@ -1134,6 +1141,29 @@ public final class IndexDefinition imple "children in [{}]", this, IndexDefinition.this); } + //In case of a pure nodetype index we just index primaryType and mixins + //and ignore any other property definition + if (nodeTypeIndex) { + boolean sync = getOptionalValue(config, LuceneIndexConstants.PROP_SYNC, false); + PropertyDefinition pdpt = createNodeTypeDefinition(this, JcrConstants.JCR_PRIMARYTYPE, sync); + PropertyDefinition pdmixin = createNodeTypeDefinition(this, JcrConstants.JCR_MIXINTYPES, sync); + + propDefns.put(pdpt.name.toLowerCase(Locale.ENGLISH), pdpt); + propDefns.put(pdmixin.name.toLowerCase(Locale.ENGLISH), pdmixin); + + if (sync) { + syncProps.add(pdpt); + syncProps.add(pdmixin); + } + + if (propNode.getChildNodeCount(1) > 0) { + log.warn("Index at [{}] has {} enabled and cannot support other property " + + "definitions", indexPath, LuceneIndexConstants.PROP_INDEX_NODE_TYPE); + } + + return ImmutableMap.copyOf(propDefns); + } + //Include all immediate child nodes to 'properties' node by default Tree propTree = TreeFactory.createReadOnlyTree(propNode); for (Tree prop : propTree.getChildren()) { @@ -1235,6 +1265,10 @@ public final class IndexDefinition imple } private boolean areAlMatchingNodeByTypeIndexed(){ + if (nodeTypeIndex) { + return true; + } + if (nodeFullTextIndexed){ return true; } @@ -1791,4 +1825,15 @@ public final class IndexDefinition imple return map.build(); } + private static PropertyDefinition createNodeTypeDefinition(IndexingRule rule, String name, boolean sync) { + NodeBuilder builder = EMPTY_NODE.builder(); + //A nodetype index just required propertyIndex and sync flags to be set + builder.setProperty(LuceneIndexConstants.PROP_PROPERTY_INDEX, true); + if (sync) { + builder.setProperty(LuceneIndexConstants.PROP_SYNC, sync); + } + builder.setProperty(LuceneIndexConstants.PROP_NAME, name); + return new PropertyDefinition(rule, name, builder.getNodeState()); + } + } Modified: jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexConstants.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexConstants.java?rev=1812274&r1=1812273&r2=1812274&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexConstants.java (original) +++ jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexConstants.java Mon Oct 16 10:22:51 2017 @@ -388,4 +388,10 @@ public interface LuceneIndexConstants { * Boolean property which signal LuceneIndexEditor to refresh the stored index definition */ String PROP_REFRESH_DEFN = "refresh"; + + /** + * Boolean property to indicate that nodes nodetype matching indexRule name + * should be indexed + */ + String PROP_INDEX_NODE_TYPE = "nodeTypeIndex"; } Modified: jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/util/IndexDefinitionBuilder.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/util/IndexDefinitionBuilder.java?rev=1812274&r1=1812273&r2=1812274&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/util/IndexDefinitionBuilder.java (original) +++ jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/util/IndexDefinitionBuilder.java Mon Oct 16 10:22:51 2017 @@ -126,6 +126,11 @@ public final class IndexDefinitionBuilde return this; } + public IndexDefinitionBuilder nodeTypeIndex() { + tree.setProperty(LuceneIndexConstants.PROP_INDEX_NODE_TYPE, true); + return this; + } + public Tree getBuilderTree(){ return tree; } @@ -205,6 +210,11 @@ public final class IndexDefinitionBuilde return this; } + public IndexRule sync() { + indexRule.setProperty(LuceneIndexConstants.PROP_SYNC, true); + return this; + } + public PropertyRule property(String name){ return property(name, false); } Modified: jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/IndexDefinitionTest.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/IndexDefinitionTest.java?rev=1812274&r1=1812273&r2=1812274&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/IndexDefinitionTest.java (original) +++ jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/IndexDefinitionTest.java Mon Oct 16 10:22:51 2017 @@ -1007,6 +1007,113 @@ public class IndexDefinitionTest { assertTrue(defn.hasSyncPropertyDefinitions()); } + //~----------------------------------< nodetype > + + + String testNodeTypeDefn = "[oak:TestMixA]\n" + + " mixin\n" + + "\n" + + "[oak:TestSuperType]\n" + + "- * (UNDEFINED) multiple\n" + + "\n" + + "[oak:TestTypeA] > oak:TestSuperType\n" + + "- * (UNDEFINED) multiple\n" + + "\n" + + "[oak:TestTypeB] > oak:TestSuperType, oak:TestMixA\n" + + "- * (UNDEFINED) multiple"; + + @Test + public void nodeTypeIndexed() throws Exception{ + TestUtil.registerNodeType(builder, testNodeTypeDefn); + root = builder.getNodeState(); + + + IndexDefinitionBuilder defnb = new IndexDefinitionBuilder(); + defnb.nodeTypeIndex(); + defnb.indexRule("oak:TestSuperType"); + + IndexDefinition defn = IndexDefinition.newBuilder(root, defnb.build(), "/foo").build(); + assertFalse(defn.hasSyncPropertyDefinitions()); + + IndexingRule ruleSuper = getRule(defn, "oak:TestSuperType"); + assertNotNull(ruleSuper); + assertTrue(defn.isPureNodeTypeIndex()); + assertTrue(ruleSuper.getConfig(JcrConstants.JCR_PRIMARYTYPE).propertyIndex); + assertTrue(ruleSuper.getConfig(JcrConstants.JCR_MIXINTYPES).propertyIndex); + assertTrue(ruleSuper.indexesAllNodesOfMatchingType()); + + assertNotNull(getRule(defn, "oak:TestTypeA")); + assertTrue(getRule(defn, "oak:TestTypeA").indexesAllNodesOfMatchingType()); + assertNotNull(getRule(defn, "oak:TestTypeB")); + assertNull(getRule(defn, "oak:TestMixA")); + } + + @Test + public void nodeTypeIndexedSync() throws Exception{ + TestUtil.registerNodeType(builder, testNodeTypeDefn); + root = builder.getNodeState(); + + IndexDefinitionBuilder defnb = new IndexDefinitionBuilder(); + defnb.nodeTypeIndex(); + defnb.indexRule("oak:TestSuperType").sync(); + + IndexDefinition defn = IndexDefinition.newBuilder(root, defnb.build(), "/foo").build(); + assertTrue(defn.hasSyncPropertyDefinitions()); + + IndexingRule ruleSuper = getRule(defn, "oak:TestSuperType"); + assertNotNull(ruleSuper); + assertTrue(defn.isPureNodeTypeIndex()); + assertTrue(ruleSuper.getConfig(JcrConstants.JCR_PRIMARYTYPE).propertyIndex); + assertTrue(ruleSuper.getConfig(JcrConstants.JCR_PRIMARYTYPE).sync); + assertTrue(ruleSuper.getConfig(JcrConstants.JCR_MIXINTYPES).propertyIndex); + assertTrue(ruleSuper.getConfig(JcrConstants.JCR_MIXINTYPES).sync); + assertTrue(ruleSuper.indexesAllNodesOfMatchingType()); + } + + @Test + public void nodeTypeIndexed_IgnoreOtherProps() throws Exception{ + TestUtil.registerNodeType(builder, testNodeTypeDefn); + root = builder.getNodeState(); + + IndexDefinitionBuilder defnb = new IndexDefinitionBuilder(); + defnb.nodeTypeIndex(); + defnb.indexRule("oak:TestSuperType").sync(); + defnb.indexRule("oak:TestSuperType").property("foo").propertyIndex(); + + + IndexDefinition defn = IndexDefinition.newBuilder(root, defnb.build(), "/foo").build(); + + IndexingRule ruleSuper = getRule(defn, "oak:TestSuperType"); + assertNotNull(ruleSuper); + + assertNull(ruleSuper.getConfig("foo")); + assertNotNull(ruleSuper.getConfig(JcrConstants.JCR_PRIMARYTYPE)); + assertNotNull(ruleSuper.getConfig(JcrConstants.JCR_MIXINTYPES)); + } + + @Test + public void nodeTypeIndex_mixin() throws Exception{ + TestUtil.registerNodeType(builder, testNodeTypeDefn); + root = builder.getNodeState(); + + + IndexDefinitionBuilder defnb = new IndexDefinitionBuilder(); + defnb.nodeTypeIndex(); + defnb.indexRule("oak:TestMixA"); + + IndexDefinition defn = IndexDefinition.newBuilder(root, defnb.build(), "/foo").build(); + assertFalse(defn.hasSyncPropertyDefinitions()); + + + assertNotNull(getRule(defn, "oak:TestTypeB")); + assertTrue(getRule(defn, "oak:TestTypeB").indexesAllNodesOfMatchingType()); + assertNotNull(getRule(defn, "oak:TestMixA")); + assertTrue(getRule(defn, "oak:TestMixA").indexesAllNodesOfMatchingType()); + + assertNull(getRule(defn, "oak:TestTypeA")); + assertNull(getRule(defn, "oak:TestSuperType")); + } + //TODO indexesAllNodesOfMatchingType - with nullCheckEnabled private static IndexingRule getRule(IndexDefinition defn, String typeName){ Modified: jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/IndexPlannerTest.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/IndexPlannerTest.java?rev=1812274&r1=1812273&r2=1812274&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/IndexPlannerTest.java (original) +++ jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/IndexPlannerTest.java Mon Oct 16 10:22:51 2017 @@ -1123,6 +1123,73 @@ public class IndexPlannerTest { assertNull(hr); } + //~----------------------------------------< nodetype > + + String testNodeTypeDefn = "[oak:TestMixA]\n" + + " mixin\n" + + "\n" + + "[oak:TestSuperType]\n" + + "- * (UNDEFINED) multiple\n" + + "\n" + + "[oak:TestTypeA] > oak:TestSuperType\n" + + "- * (UNDEFINED) multiple\n" + + "\n" + + "[oak:TestTypeB] > oak:TestSuperType, oak:TestMixA\n" + + "- * (UNDEFINED) multiple"; + + @Test + public void nodetype_primaryType() throws Exception{ + TestUtil.registerNodeType(builder, testNodeTypeDefn); + root = builder.getNodeState(); + + IndexDefinitionBuilder defnb = new IndexDefinitionBuilder(); + defnb.nodeTypeIndex(); + defnb.indexRule("oak:TestSuperType"); + + IndexDefinition defn = new IndexDefinition(root, defnb.build(), "/foo"); + IndexNode node = createIndexNode(defn); + + FilterImpl filter = createFilter("oak:TestSuperType"); + + IndexPlanner planner = new IndexPlanner(node, "/foo", filter, Collections.<OrderEntry>emptyList()); + QueryIndex.IndexPlan plan = planner.getPlan(); + assertNotNull(plan); + + IndexPlanner.PlanResult r = pr(plan); + assertTrue(r.evaluateNodeTypeRestriction()); + + //As oak:TestSuperType is parent of oak:TestTypeA the child nodetypes should + //also be indexed + filter = createFilter("oak:TestTypeA"); + planner = new IndexPlanner(node, "/foo", filter, Collections.<OrderEntry>emptyList()); + plan = planner.getPlan(); + + assertNotNull(plan); + r = pr(plan); + assertTrue(r.evaluateNodeTypeRestriction()); + } + + @Test + public void nodetype_mixin() throws Exception{ + TestUtil.registerNodeType(builder, testNodeTypeDefn); + root = builder.getNodeState(); + + IndexDefinitionBuilder defnb = new IndexDefinitionBuilder(); + defnb.nodeTypeIndex(); + defnb.indexRule("oak:TestMixA"); + + IndexDefinition defn = new IndexDefinition(root, defnb.build(), "/foo"); + IndexNode node = createIndexNode(defn); + + FilterImpl filter = createFilter("oak:TestMixA"); + + IndexPlanner planner = new IndexPlanner(node, "/foo", filter, Collections.<OrderEntry>emptyList()); + QueryIndex.IndexPlan plan = planner.getPlan(); + assertNotNull(plan); + + IndexPlanner.PlanResult r = pr(plan); + assertTrue(r.evaluateNodeTypeRestriction()); + } private IndexPlanner createPlannerForFulltext(NodeState defn, FullTextExpression exp) throws IOException { IndexNode node = createIndexNode(new IndexDefinition(root, defn, "/foo")); Modified: jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LucenePropertyIndexTest.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LucenePropertyIndexTest.java?rev=1812274&r1=1812273&r2=1812274&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LucenePropertyIndexTest.java (original) +++ jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LucenePropertyIndexTest.java Mon Oct 16 10:22:51 2017 @@ -2506,6 +2506,51 @@ public class LucenePropertyIndexTest ext } @Test + public void subNodeTypes_nodeTypeIndex() throws Exception{ + optionalEditorProvider.delegate = new TypeEditorProvider(); + String testNodeTypes = + "[oak:TestMixA]\n" + + " mixin\n" + + "\n" + + "[oak:TestSuperType] \n" + + " - * (UNDEFINED) multiple\n" + + "\n" + + "[oak:TestTypeA] > oak:TestSuperType\n" + + " - * (UNDEFINED) multiple\n" + + "\n" + + " [oak:TestTypeB] > oak:TestSuperType, oak:TestMixA\n" + + " - * (UNDEFINED) multiple\n" + + "\n" + + " [oak:TestTypeC] > oak:TestMixA\n" + + " - * (UNDEFINED) multiple"; + NodeTypeRegistry.register(root, IOUtils.toInputStream(testNodeTypes, "utf-8"), "test nodeType"); + //Flush the changes to nodetypes + root.commit(); + + IndexDefinitionBuilder idxb = new IndexDefinitionBuilder().noAsync(); + idxb.nodeTypeIndex(); + idxb.indexRule("oak:TestSuperType"); + idxb.indexRule("oak:TestMixA"); + + Tree idx = root.getTree("/").getChild("oak:index").addChild("test1"); + idxb.build(idx); + + root.getTree("/oak:index/nodetype").remove(); + + Tree rootTree = root.getTree("/"); + createNodeWithType(rootTree, "a", "oak:TestTypeA"); + createNodeWithType(rootTree, "b", "oak:TestTypeB"); + createNodeWithMixinType(rootTree, "c", "oak:TestMixA") + .setProperty(JcrConstants.JCR_PRIMARYTYPE, "oak:Unstructured", Type.NAME); + + root.commit(); + + assertPlanAndQuery("select * from [oak:TestSuperType]", "lucene:test1(/oak:index/test1)", asList("/a", "/b")); + assertPlanAndQuery("select * from [oak:TestMixA]", "lucene:test1(/oak:index/test1)", asList("/b", "/c")); + } + + + @Test public void indexDefinitionModifiedPostReindex() throws Exception{ IndexDefinitionBuilder idxb = new IndexDefinitionBuilder().noAsync(); idxb.indexRule("nt:base").property("foo").propertyIndex(); Modified: jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/util/IndexDefinitionBuilderTest.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/util/IndexDefinitionBuilderTest.java?rev=1812274&r1=1812273&r2=1812274&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/util/IndexDefinitionBuilderTest.java (original) +++ jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/util/IndexDefinitionBuilderTest.java Mon Oct 16 10:22:51 2017 @@ -278,4 +278,30 @@ public class IndexDefinitionBuilderTest updated.setProperty("type", "foo"); assertEquals("lucene", new IndexDefinitionBuilder(updated).build().getString("type")); } + + @Test + public void nodeTypeIndex() throws Exception{ + builder.nodeTypeIndex(); + builder.indexRule("nt:file"); + + NodeState state = builder.build(); + assertTrue(state.getChildNode("indexRules").exists()); + NodeState ntFileRule = state.getChildNode("indexRules").getChildNode("nt:file"); + assertTrue(ntFileRule.exists()); + assertTrue(state.getBoolean(LuceneIndexConstants.PROP_INDEX_NODE_TYPE)); + assertFalse(ntFileRule.getBoolean(LuceneIndexConstants.PROP_SYNC)); + } + + @Test + public void nodeTypeIndexSync() throws Exception{ + builder.nodeTypeIndex(); + builder.indexRule("nt:file").sync(); + + NodeState state = builder.build(); + assertTrue(state.getChildNode("indexRules").exists()); + NodeState ntFileRule = state.getChildNode("indexRules").getChildNode("nt:file"); + assertTrue(ntFileRule.exists()); + assertTrue(state.getBoolean(LuceneIndexConstants.PROP_INDEX_NODE_TYPE)); + assertTrue(ntFileRule.getBoolean(LuceneIndexConstants.PROP_SYNC)); + } } \ No newline at end of file