Index: oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexQueryTest.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/LuceneIndexQueryTest.java (date 1435662951000) +++ oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexQueryTest.java (revision ) @@ -19,6 +19,7 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; +import java.util.ArrayList; import java.util.Calendar; import java.util.Iterator; import java.util.List; @@ -27,6 +28,7 @@ import org.apache.jackrabbit.oak.api.ContentRepository; 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.plugins.nodetype.write.InitialContent; import org.apache.jackrabbit.oak.query.AbstractQueryTest; import org.apache.jackrabbit.oak.spi.commit.Observer; @@ -35,6 +37,7 @@ import org.junit.Ignore; import org.junit.Test; +import static com.google.common.collect.ImmutableList.of; import static java.util.Arrays.asList; import static junit.framework.Assert.assertEquals; import static org.apache.jackrabbit.JcrConstants.JCR_PRIMARYTYPE; @@ -471,8 +474,35 @@ "ORDER BY " + added + " DESC "; assertQuery(statement, SQL2, expected); + } + + @Test + public void testMultiValuedPropUpdate() throws Exception { + Tree test = root.getTree("/").addChild("test"); + String child = "child"; + String mulValuedProp = "prop"; + test.addChild(child).setProperty(mulValuedProp, of("foo","bar"), Type.STRINGS); + root.commit(); + assertQuery( + "/jcr:root//*[jcr:contains(@" + mulValuedProp + ", 'foo')]", + "xpath", of("/test/" + child)); + test.getChild(child).setProperty(mulValuedProp, new ArrayList(), Type.STRINGS); + root.commit(); + assertQuery("/jcr:root//*[jcr:contains(@" + mulValuedProp + ", 'foo')]", "xpath", new ArrayList()); + + test.getChild(child).setProperty(mulValuedProp, of("bar"), Type.STRINGS); + root.commit(); + assertQuery( + "/jcr:root//*[jcr:contains(@" + mulValuedProp + ", 'foo')]", + "xpath", new ArrayList()); + + test.getChild(child).removeProperty(mulValuedProp); + root.commit(); + assertQuery( + "/jcr:root//*[jcr:contains(@" + mulValuedProp + ", 'foo')]", + "xpath", new ArrayList()); } - + @SuppressWarnings("unused") private static void walktree(final Tree t) { System.out.println("+ " + t.getPath()); Index: oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexEditor.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/LuceneIndexEditor.java (date 1435662951000) +++ oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexEditor.java (revision ) @@ -100,6 +100,8 @@ private boolean propertiesChanged = false; + private List propertiesModified = Lists.newArrayList(); + private final NodeState root; /** @@ -221,13 +223,19 @@ @Override public void propertyChanged(PropertyState before, PropertyState after) { - markPropertyChanged(before.getName()); + boolean changed = markPropertyChanged(before.getName()); + if (changed) { + propertiesModified.add(before); + } checkAggregates(before.getName()); } @Override public void propertyDeleted(PropertyState before) { - markPropertyChanged(before.getName()); + boolean deleted = markPropertyChanged(before.getName()); + if (deleted) { + propertiesModified.add(before); + } checkAggregates(before.getName()); } @@ -333,6 +341,10 @@ dirty |= indexNullCheckEnabledProps(path, fields, state); dirty |= indexNotNullCheckEnabledProps(path, fields, state); + if (!dirty) { + dirty = indexIfSinglePropertyRemoved(); + } + if (isUpdate && !dirty) { // updated the state but had no relevant changes return null; @@ -575,7 +587,20 @@ } return fieldAdded; } - + + private boolean indexIfSinglePropertyRemoved() { + boolean dirty = false; + for (PropertyState ps : propertiesModified) { + PropertyDefinition pd = indexingRule.getConfig(ps.getName()); + if (pd != null && pd.index && (pd.includePropertyType(ps.getType().tag()) || indexingRule + .includePropertyType(ps.getType().tag()))) { + dirty = true; + break; + } + } + return dirty; + } + /** * Determine if the property as defined by PropertyDefinition exists or not. * @@ -781,12 +806,14 @@ } } - private void markPropertyChanged(String name) { + private boolean markPropertyChanged(String name) { if (isIndexable() && !propertiesChanged && indexingRule.isIndexed(name)) { propertiesChanged = true; + return true; } + return false; } private IndexDefinition getDefinition() {