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 ch...@apache.org on 2014/11/12 14:13:52 UTC
svn commit: r1638781 - in /jackrabbit/oak/trunk/oak-lucene/src:
main/java/org/apache/jackrabbit/oak/plugins/index/lucene/
test/java/org/apache/jackrabbit/oak/plugins/index/lucene/
Author: chetanm
Date: Wed Nov 12 13:13:52 2014
New Revision: 1638781
URL: http://svn.apache.org/r1638781
Log:
OAK-2261 - Enable support for NodeType based indexing rules (WIP)
Add support for IndexRule configuration parsing
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/PropertyDefinition.java
jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/IndexDefinitionTest.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=1638781&r1=1638780&r2=1638781&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 Wed Nov 12 13:13:52 2014
@@ -19,25 +19,39 @@
package org.apache.jackrabbit.oak.plugins.index.lucene;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
+import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.regex.Pattern;
import javax.annotation.CheckForNull;
import javax.jcr.PropertyType;
+import javax.jcr.RepositoryException;
+import javax.jcr.nodetype.NodeTypeIterator;
+import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
+import org.apache.jackrabbit.JcrConstants;
import org.apache.jackrabbit.oak.api.PropertyState;
+import org.apache.jackrabbit.oak.api.Tree;
import org.apache.jackrabbit.oak.api.Type;
+import org.apache.jackrabbit.oak.core.ImmutableRoot;
+import org.apache.jackrabbit.oak.namepath.NamePathMapper;
import org.apache.jackrabbit.oak.plugins.index.lucene.util.LuceneIndexHelper;
+import org.apache.jackrabbit.oak.plugins.nodetype.ReadOnlyNodeTypeManager;
+import org.apache.jackrabbit.oak.spi.state.ChildNodeEntry;
import org.apache.jackrabbit.oak.spi.state.NodeState;
+import org.apache.jackrabbit.oak.util.TreeUtil;
import org.apache.lucene.codecs.Codec;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import static com.google.common.collect.Lists.newArrayList;
import static com.google.common.collect.Maps.newHashMap;
import static com.google.common.collect.Sets.newHashSet;
import static org.apache.jackrabbit.oak.plugins.index.IndexConstants.DECLARING_NODE_TYPES;
@@ -46,10 +60,12 @@ import static org.apache.jackrabbit.oak.
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;
+import static org.apache.jackrabbit.oak.plugins.index.lucene.LuceneIndexConstants.FIELD_BOOST;
import static org.apache.jackrabbit.oak.plugins.index.lucene.LuceneIndexConstants.FULL_TEXT_ENABLED;
import static org.apache.jackrabbit.oak.plugins.index.lucene.LuceneIndexConstants.INCLUDE_PROPERTY_NAMES;
import static org.apache.jackrabbit.oak.plugins.index.lucene.LuceneIndexConstants.INCLUDE_PROPERTY_TYPES;
import static org.apache.jackrabbit.oak.plugins.index.lucene.LuceneIndexConstants.ORDERED_PROP_NAMES;
+import static org.apache.jackrabbit.oak.plugins.index.lucene.PropertyDefinition.DEFAULT_BOOST;
import static org.apache.jackrabbit.oak.plugins.index.lucene.util.ConfigUtil.getOptionalValue;
class IndexDefinition {
@@ -104,6 +120,11 @@ class IndexDefinition {
*/
private final long entryCount;
+ /**
+ * The {@link IndexingRule}s inside this configuration. Keys being the NodeType names
+ */
+ private final Map<String, List<IndexingRule>> indexRules;
+
public IndexDefinition(NodeState root, NodeState defn) {
this.root = root;
this.definition = defn;
@@ -135,6 +156,9 @@ class IndexDefinition {
//TODO Flag out invalid propertyNames like one which are absolute
this.relativeProps = collectRelativeProps(Iterables.concat(includes, orderedProps));
this.propDefns = collectPropertyDefns(defn);
+
+ this.indexRules = collectIndexRules(defn.getChildNode(LuceneIndexConstants.INDEX_RULES));
+
this.relativePropNames = collectRelPropertyNames(this.relativeProps.values());
this.relativePropsMaxLevels = getRelPropertyMaxLevels(this.relativeProps.values());
@@ -335,6 +359,238 @@ class IndexDefinition {
return codec;
}
+ //~---------------------------------------------------< IndexRule >
+
+ /**
+ * Returns the first indexing rule that applies to the given node
+ * <code>state</code>.
+ *
+ * @param state a node state.
+ * @return the indexing rule or <code>null</code> if none applies.
+ */
+ public IndexingRule getApplicableIndexingRule(Tree state) {
+ List<IndexingRule> rules = null;
+ List<IndexingRule> r = indexRules.get(getPrimaryTypeName(state));
+ if (r != null) {
+ rules = new ArrayList<IndexingRule>();
+ rules.addAll(r);
+ }
+
+ for (String name : getMixinTypeNames(state)) {
+ r = indexRules.get(name);
+ if (r != null) {
+ if (rules == null) {
+ rules = new ArrayList<IndexingRule>();
+ }
+ rules.addAll(r);
+ }
+ }
+
+ if (rules != null) {
+ for (IndexingRule rule : rules) {
+ if (rule.appliesTo(state)) {
+ return rule;
+ }
+ }
+ }
+
+ // no applicable rule
+ return null;
+ }
+
+ private Map<String, List<IndexingRule>> collectIndexRules(NodeState indexRules){
+ //TODO if a rule is defined for nt:base then this map would have entry for each
+ //registered nodeType in the system
+
+ //TODO Add check that children are orderable
+
+ Map<String, List<IndexingRule>> nt2rules = newHashMap();
+ ReadOnlyNodeTypeManager ntReg = ReadOnlyNodeTypeManager.getInstance(new ImmutableRoot(root),
+ NamePathMapper.DEFAULT);
+
+ for (ChildNodeEntry ruleEntry : indexRules.getChildNodeEntries()) {
+ IndexingRule rule = new IndexingRule(ruleEntry.getName(), ruleEntry.getNodeState());
+ // register under node type and all its sub types
+ log.debug("Found rule '{}' for NodeType '{}'", rule, rule.getNodeTypeName());
+ NodeTypeIterator ntItr = getAllNodeTypes(ntReg);
+ while (ntItr.hasNext()) {
+ String ntName = ntItr.nextNodeType().getName();
+
+ if (ntReg.isNodeType(ntName, rule.getNodeTypeName())) {
+ List<IndexingRule> perNtConfig = nt2rules.get(ntName);
+ if (perNtConfig == null) {
+ perNtConfig = new ArrayList<IndexingRule>();
+ nt2rules.put(ntName, perNtConfig);
+ }
+ log.debug("Registering it for name '{}'", ntName);
+ perNtConfig.add(new IndexingRule(rule, ntName));
+ }
+ }
+ }
+
+ for (Map.Entry<String, List<IndexingRule>> e : nt2rules.entrySet()){
+ e.setValue(ImmutableList.copyOf(e.getValue()));
+ }
+
+ return ImmutableMap.copyOf(nt2rules);
+ }
+
+ public class IndexingRule {
+ private final String nodeTypeName;
+ private final Map<String, PropertyDefinition> propConfigs;
+ private final List<NamePattern> namePatterns;
+ final float boost;
+
+ IndexingRule(String nodeTypeName, NodeState config) {
+ this.nodeTypeName = nodeTypeName;
+ this.boost = getOptionalValue(config, FIELD_BOOST, DEFAULT_BOOST);
+ this.propConfigs = collectPropConfigs(config);
+ this.namePatterns = collectNamePatterns(propConfigs.values());
+ }
+
+ /**
+ * Creates a new indexing rule base on an existing one, but for a
+ * different node type name.
+ *
+ * @param original the existing rule.
+ * @param nodeTypeName the node type name for the rule.
+ */
+ IndexingRule(IndexingRule original, String nodeTypeName) {
+ this.nodeTypeName = nodeTypeName;
+ this.propConfigs = original.propConfigs;
+ this.namePatterns = original.namePatterns;
+ this.boost = original.boost;
+ }
+
+ /**
+ * Returns <code>true</code> if the property with the given name is
+ * indexed according to this rule.
+ *
+ * @param propertyName the name of a property.
+ * @return <code>true</code> if the property is indexed;
+ * <code>false</code> otherwise.
+ */
+ public boolean isIndexed(String propertyName) {
+ return getConfig(propertyName) != null;
+ }
+
+
+ /**
+ * Returns the name of the node type where this rule applies to.
+ *
+ * @return name of the node type.
+ */
+ public String getNodeTypeName() {
+ return nodeTypeName;
+ }
+
+ /**
+ * Returns <code>true</code> if this rule applies to the given node
+ * <code>state</code>.
+ *
+ * @param state the state to check.
+ * @return <code>true</code> the rule applies to the given node;
+ * <code>false</code> otherwise.
+ */
+ private boolean appliesTo(Tree state) {
+ if (!nodeTypeName.equals(getPrimaryTypeName(state))) {
+ return false;
+ }
+ //TODO Add support for condition
+ //return condition == null || condition.evaluate(state);
+ return true;
+ }
+
+ /**
+ * @param propertyName name of a property.
+ * @return the property configuration or <code>null</code> if this
+ * indexing rule does not contain a configuration for the given
+ * property.
+ */
+ @CheckForNull
+ public PropertyDefinition getConfig(String propertyName) {
+ PropertyDefinition config = propConfigs.get(propertyName);
+ if (config != null) {
+ return config;
+ } else if (namePatterns.size() > 0) {
+ // check patterns
+ for (NamePattern np : namePatterns) {
+ if (np.matches(propertyName)) {
+ return np.getConfig();
+ }
+ }
+ }
+ return null;
+ }
+
+ private Map<String, PropertyDefinition> collectPropConfigs(NodeState config) {
+ Map<String, PropertyDefinition> propDefns = newHashMap();
+ NodeState propNode = config.getChildNode(LuceneIndexConstants.PROP_NODE);
+ //Include all immediate child nodes to 'properties' node by default
+ for (String propName : propNode.getChildNodeNames()) {
+ NodeState propDefnNode = propNode.getChildNode(propName);
+ if (propDefnNode.exists() && !propDefns.containsKey(propName)) {
+ PropertyDefinition pd = new PropertyDefinition(IndexDefinition.this, propName, propDefnNode);
+ propDefns.put(pd.name, pd);
+ }
+ }
+ return ImmutableMap.copyOf(propDefns);
+ }
+
+ private List<NamePattern> collectNamePatterns(Collection<PropertyDefinition> propConfigs) {
+ List<NamePattern> patterns = newArrayList();
+ for (PropertyDefinition pd : propConfigs) {
+ if (pd.isRegexp) {
+ patterns.add(new NamePattern(pd.name, pd));
+ }
+ }
+ return ImmutableList.copyOf(patterns);
+ }
+ }
+
+ /**
+ * A property name pattern.
+ */
+ private static final class NamePattern {
+ /**
+ * The pattern to match.
+ */
+ private final Pattern pattern;
+
+ /**
+ * The associated configuration.
+ */
+ private final PropertyDefinition config;
+
+ /**
+ * Creates a new name pattern.
+ *
+ * @param pattern the pattern as defined by the property definition
+ * @param config the associated configuration.
+ */
+ private NamePattern(String pattern,
+ PropertyDefinition config){
+
+ this.pattern = Pattern.compile(pattern);
+ this.config = config;
+ }
+
+ /**
+ * @param path property name to match
+ * @return <code>true</code> if <code>property name</code> matches this name
+ * pattern; <code>false</code> otherwise.
+ */
+ boolean matches(String propertyPath) {
+ return pattern.matcher(propertyPath).matches();
+ }
+
+ PropertyDefinition getConfig() {
+ return config;
+ }
+ }
+
+ //~---------------------------------------------< utility >
+
private static Set<String> getMultiProperty(NodeState definition, String propName){
PropertyState pse = definition.getProperty(propName);
return pse != null ? ImmutableSet.copyOf(pse.getValue(Type.STRINGS)) : Collections.<String>emptySet();
@@ -347,4 +603,23 @@ class IndexDefinition {
}
return ImmutableSet.copyOf(result);
}
+
+ private static NodeTypeIterator getAllNodeTypes(ReadOnlyNodeTypeManager ntReg) {
+ try {
+ return ntReg.getAllNodeTypes();
+ } catch (RepositoryException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private static String getPrimaryTypeName(Tree state) {
+ String primaryType = TreeUtil.getPrimaryTypeName(state);
+ //In case not a proper JCR assume nt:base
+ return primaryType != null ? primaryType : "nt:base";
+ }
+
+ private static Iterable<String> getMixinTypeNames(Tree tree) {
+ PropertyState property = tree.getProperty(JcrConstants.JCR_MIMETYPE);
+ return property != null ? property.getValue(Type.NAMES) : Collections.<String>emptyList();
+ }
}
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=1638781&r1=1638780&r2=1638781&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 Wed Nov 12 13:13:52 2014
@@ -101,9 +101,17 @@ public interface LuceneIndexConstants {
*/
String PROP_NODE = "properties";
+ String INDEX_RULES = "indexRules";
+
/**
* Field boost factor
*/
String FIELD_BOOST = "boost";
+ /**
+ * Property name defined explicitly. Mostly used in case of relative property names
+ */
+ String PROP_NAME = "name";
+
+ String PROP_IS_REGEX = "isRegexp";
}
Modified: jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/PropertyDefinition.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/PropertyDefinition.java?rev=1638781&r1=1638780&r2=1638781&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/PropertyDefinition.java (original)
+++ jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/PropertyDefinition.java Wed Nov 12 13:13:52 2014
@@ -21,11 +21,14 @@ package org.apache.jackrabbit.oak.plugin
import javax.jcr.PropertyType;
+import org.apache.jackrabbit.oak.api.PropertyState;
+import org.apache.jackrabbit.oak.api.Type;
import org.apache.jackrabbit.oak.spi.state.NodeState;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static org.apache.jackrabbit.oak.plugins.index.lucene.LuceneIndexConstants.FIELD_BOOST;
+import static org.apache.jackrabbit.oak.plugins.index.lucene.LuceneIndexConstants.PROP_IS_REGEX;
import static org.apache.jackrabbit.oak.plugins.index.lucene.util.ConfigUtil.getOptionalValue;
class PropertyDefinition {
@@ -33,10 +36,16 @@ class PropertyDefinition {
/**
* The default boost: 1.0f.
*/
- private static final float DEFAULT_BOOST = 1.0f;
+ static final float DEFAULT_BOOST = 1.0f;
- private final String name;
private final NodeState definition;
+ /**
+ * Property name. By default derived from the NodeState name which has the
+ * property definition. However in case property name is a pattern, relative
+ * property etc then it should be defined via 'name' property in NodeState.
+ * In such case NodeState name can be set to anything
+ */
+ final String name;
final int propertyType;
/**
@@ -44,8 +53,11 @@ class PropertyDefinition {
*/
final float boost;
+ final boolean isRegexp;
+
public PropertyDefinition(IndexDefinition idxDefn, String name, NodeState defn) {
- this.name = name;
+ this.isRegexp = getOptionalValue(defn, PROP_IS_REGEX, false);
+ this.name = getName(defn, name);
this.definition = defn;
this.boost = getOptionalValue(defn, FIELD_BOOST, DEFAULT_BOOST);
this.propertyType = getPropertyType(idxDefn, name, defn);
@@ -55,6 +67,13 @@ class PropertyDefinition {
return propertyType;
}
+ //~---------------------------------------------< internal >
+
+ private static String getName(NodeState definition, String defaultName){
+ PropertyState ps = definition.getProperty(LuceneIndexConstants.PROP_NAME);
+ return ps == null ? defaultName : ps.getValue(Type.STRING);
+ }
+
private static int getPropertyType(IndexDefinition idxDefn, String name, NodeState defn) {
int type = PropertyType.UNDEFINED;
if (defn.hasProperty(LuceneIndexConstants.PROP_TYPE)) {
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=1638781&r1=1638780&r2=1638781&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 Wed Nov 12 13:13:52 2014
@@ -22,17 +22,25 @@ package org.apache.jackrabbit.oak.plugin
import javax.jcr.PropertyType;
import com.google.common.collect.Iterables;
+import org.apache.jackrabbit.JcrConstants;
+import org.apache.jackrabbit.oak.api.Tree;
+import org.apache.jackrabbit.oak.commons.PathUtils;
+import org.apache.jackrabbit.oak.plugins.tree.ImmutableTree;
import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
import org.apache.jackrabbit.oak.spi.state.NodeState;
import org.apache.lucene.codecs.Codec;
+import org.apache.jackrabbit.oak.plugins.index.lucene.IndexDefinition.IndexingRule;
import org.junit.Test;
+import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.collect.ImmutableSet.of;
import static javax.jcr.PropertyType.TYPENAME_LONG;
import static org.apache.jackrabbit.oak.api.Type.STRINGS;
import static org.apache.jackrabbit.oak.plugins.index.lucene.LuceneIndexConstants.INCLUDE_PROPERTY_NAMES;
import static org.apache.jackrabbit.oak.plugins.index.lucene.LuceneIndexConstants.INCLUDE_PROPERTY_TYPES;
+import static org.apache.jackrabbit.oak.plugins.index.lucene.LuceneIndexConstants.INDEX_RULES;
import static org.apache.jackrabbit.oak.plugins.index.lucene.LuceneIndexConstants.PROP_NODE;
+import static org.apache.jackrabbit.oak.plugins.memory.EmptyNodeState.EMPTY_NODE;
import static org.apache.jackrabbit.oak.plugins.memory.PropertyStates.createProperty;
import static org.apache.jackrabbit.oak.plugins.nodetype.write.InitialContent.INITIAL_CONTENT;
import static org.junit.Assert.assertEquals;
@@ -144,4 +152,83 @@ public class IndexDefinitionTest {
assertEquals(PropertyType.DATE, defn.getPropDefn("foo1/bar").getPropertyType());
assertEquals(PropertyType.LONG, defn.getPropDefn("foo2/bar2/baz").getPropertyType());
}
+
+ @Test
+ public void indexRuleSanity() throws Exception{
+ NodeBuilder rules = builder.child(INDEX_RULES);
+ rules.child("nt:folder").setProperty(LuceneIndexConstants.FIELD_BOOST, 2.0);
+ child(rules, "nt:folder/properties/prop1")
+ .setProperty(LuceneIndexConstants.FIELD_BOOST, 3.0)
+ .setProperty(LuceneIndexConstants.PROP_TYPE, PropertyType.TYPENAME_BOOLEAN);
+
+ IndexDefinition defn = new IndexDefinition(root, builder.getNodeState());
+
+ assertNull(defn.getApplicableIndexingRule(newTree(newNode("nt:base"))));
+
+ IndexingRule rule1 = defn.getApplicableIndexingRule(newTree(newNode("nt:folder")));
+ assertNotNull(rule1);
+ assertEquals(2.0f, rule1.boost, 0);
+
+ assertTrue(rule1.isIndexed("prop1"));
+ assertFalse(rule1.isIndexed("prop2"));
+
+ PropertyDefinition pd = rule1.getConfig("prop1");
+ assertEquals(3.0f, pd.boost, 0);
+ assertEquals(PropertyType.BOOLEAN, pd.propertyType);
+ }
+
+ @Test
+ public void indexRuleInheritance() throws Exception{
+ NodeBuilder rules = builder.child(INDEX_RULES);
+ rules.child("nt:hierarchyNode").setProperty(LuceneIndexConstants.FIELD_BOOST, 2.0);
+
+ IndexDefinition defn = new IndexDefinition(root, builder.getNodeState());
+
+ assertNull(defn.getApplicableIndexingRule(newTree(newNode("nt:base"))));
+ assertNotNull(defn.getApplicableIndexingRule(newTree(newNode("nt:hierarchyNode"))));
+ assertNotNull(defn.getApplicableIndexingRule(newTree(newNode("nt:folder"))));
+
+ //TODO Inheritance and mixin
+ }
+
+ @Test
+ public void indexRuleWithPropertyRegEx() throws Exception{
+ NodeBuilder rules = builder.child(INDEX_RULES);
+ rules.child("nt:folder");
+ child(rules, "nt:folder/properties/prop1")
+ .setProperty(LuceneIndexConstants.FIELD_BOOST, 3.0);
+ child(rules, "nt:folder/properties/prop2")
+ .setProperty(LuceneIndexConstants.PROP_NAME, "foo.*")
+ .setProperty(LuceneIndexConstants.PROP_IS_REGEX, true)
+ .setProperty(LuceneIndexConstants.FIELD_BOOST, 4.0);
+
+ IndexDefinition defn = new IndexDefinition(root, builder.getNodeState());
+
+ IndexingRule rule1 = defn.getApplicableIndexingRule(newTree(newNode("nt:folder")));
+ assertNotNull(rule1);
+
+ assertTrue(rule1.isIndexed("prop1"));
+ assertFalse(rule1.isIndexed("prop2"));
+ assertTrue(rule1.isIndexed("fooProp"));
+
+ PropertyDefinition pd = rule1.getConfig("fooProp2");
+ assertEquals(4.0f, pd.boost, 0);
+ }
+
+ private static Tree newTree(NodeBuilder nb){
+ return new ImmutableTree(nb.getNodeState());
+ }
+
+ private static NodeBuilder newNode(String typeName){
+ NodeBuilder builder = EMPTY_NODE.builder();
+ builder.setProperty(JcrConstants.JCR_PRIMARYTYPE, typeName);
+ return builder;
+ }
+
+ private static NodeBuilder child(NodeBuilder nb, String path) {
+ for (String name : PathUtils.elements(checkNotNull(path))) {
+ nb = nb.child(name);
+ }
+ return nb;
+ }
}