Author: alexparvulescu Date: Wed Apr 2 19:04:22 2014 New Revision: 1584132
URL: http://svn.apache.org/r1584132 Log: OAK-1668 Lucene should not serve queries for what it doesn't index Added: jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexExclusionQueryTest.java (with props) 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/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=1584132&r1=1584131&r2=1584132&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 Apr 2 19:04:22 2014 @@ -28,6 +28,8 @@ import static org.apache.jackrabbit.oak. import static org.apache.jackrabbit.oak.plugins.index.IndexConstants.TYPE_PROPERTY_NAME; import static org.apache.jackrabbit.oak.plugins.index.lucene.FieldNames.PATH; import static org.apache.jackrabbit.oak.plugins.index.lucene.FieldNames.PATH_SELECTOR; +import static org.apache.jackrabbit.oak.plugins.index.lucene.LuceneIndexConstants.EXCLUDE_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_DATA_CHILD_NAME; import static org.apache.jackrabbit.oak.plugins.index.lucene.LuceneIndexConstants.PERSISTENCE_FILE; import static org.apache.jackrabbit.oak.plugins.index.lucene.LuceneIndexConstants.PERSISTENCE_NAME; @@ -56,6 +58,8 @@ import java.util.List; import java.util.Set; import java.util.concurrent.atomic.AtomicReference; +import javax.jcr.PropertyType; + import org.apache.jackrabbit.oak.api.PropertyValue; import org.apache.jackrabbit.oak.plugins.index.aggregate.NodeAggregator; import org.apache.jackrabbit.oak.plugins.index.lucene.util.MoreLikeThisHelper; @@ -67,11 +71,11 @@ import org.apache.jackrabbit.oak.query.f import org.apache.jackrabbit.oak.query.fulltext.FullTextTerm; import org.apache.jackrabbit.oak.query.fulltext.FullTextVisitor; import org.apache.jackrabbit.oak.spi.query.Cursor; -import org.apache.jackrabbit.oak.spi.query.Filter; -import org.apache.jackrabbit.oak.spi.query.PropertyValues; import org.apache.jackrabbit.oak.spi.query.Cursors.PathCursor; +import org.apache.jackrabbit.oak.spi.query.Filter; import org.apache.jackrabbit.oak.spi.query.Filter.PropertyRestriction; 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.ChildNodeEntry; @@ -329,7 +333,7 @@ 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) + " ft:(" + ft + ")"; + String plan = getQuery(filter, null, nonFullTextConstraints, analyzer, getIndexDef(root)) + " ft:(" + ft + ")"; if (!parent.isEmpty()) { plan += " parent:" + parent; } @@ -363,7 +367,7 @@ public class LuceneIndex implements Full IndexSearcher searcher = new IndexSearcher(reader); List<LuceneResultRow> rows = new ArrayList<LuceneResultRow>(); Query query = getQuery(filter, reader, - nonFullTextConstraints, analyzer); + nonFullTextConstraints, analyzer, getIndexDef(root)); // TODO OAK-828 HashSet<String> seenPaths = new HashSet<String>(); @@ -428,10 +432,11 @@ public class LuceneIndex implements Full * path, node type, and so on) should be added to the Lucene * query * @param analyzer the Lucene analyzer used for building the fulltext query + * @param indexDefinition nodestate that contains the index definition * @return the Lucene query */ private static Query getQuery(Filter filter, IndexReader reader, - boolean nonFullTextConstraints, Analyzer analyzer) { + boolean nonFullTextConstraints, Analyzer analyzer, NodeState indexDefinition) { List<Query> qs = new ArrayList<Query>(); FullTextExpression ft = filter.getFullTextConstraint(); if (ft == null) { @@ -461,9 +466,9 @@ public class LuceneIndex implements Full throw new RuntimeException(e); } } - } - else if (nonFullTextConstraints) { - addNonFullTextConstraints(qs, filter, reader, analyzer); + } else if (nonFullTextConstraints) { + addNonFullTextConstraints(qs, filter, reader, analyzer, + indexDefinition); } if (qs.size() == 0) { return new MatchAllDocsQuery(); @@ -479,7 +484,7 @@ public class LuceneIndex implements Full } private static void addNonFullTextConstraints(List<Query> qs, - Filter filter, IndexReader reader, Analyzer analyzer) { + Filter filter, IndexReader reader, Analyzer analyzer, NodeState indexDefinition) { if (!filter.matchesAllTypes()) { addNodeTypeConstraints(qs, filter); } @@ -526,11 +531,12 @@ public class LuceneIndex implements Full continue; } - String name = pr.propertyName; - if (name.contains("/")) { - // lucene cannot handle child-level property restrictions + // check excluded properties and types + if (isExcludedProperty(pr, indexDefinition)) { continue; } + + String name = pr.propertyName; if ("rep:excerpt".equals(name)) { continue; } @@ -617,6 +623,44 @@ public class LuceneIndex implements Full return token; } + private static boolean isExcludedProperty(PropertyRestriction pr, + NodeState definition) { + String name = pr.propertyName; + if (name.contains("/")) { + // lucene cannot handle child-level property restrictions + return true; + } + + // check name + for (String e : definition.getStrings(EXCLUDE_PROPERTY_NAMES)) { + if (e.equalsIgnoreCase(name)) { + return true; + } + } + + // check type + Integer type = null; + if (pr.first != null) { + type = pr.first.getType().tag(); + } else if (pr.last != null) { + type = pr.last.getType().tag(); + } else if (pr.list != null && !pr.list.isEmpty()) { + type = pr.list.get(0).getType().tag(); + } + if (type != null) { + boolean isIn = false; + for (String e : definition.getStrings(INCLUDE_PROPERTY_TYPES)) { + if (PropertyType.valueFromName(e) == type) { + isIn = true; + } + } + if (!isIn) { + return true; + } + } + return false; + } + private static void addReferenceConstraint(String uuid, List<Query> qs, IndexReader reader) { if (reader == null) { Added: jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexExclusionQueryTest.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexExclusionQueryTest.java?rev=1584132&view=auto ============================================================================== --- jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexExclusionQueryTest.java (added) +++ jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexExclusionQueryTest.java Wed Apr 2 19:04:22 2014 @@ -0,0 +1,109 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jackrabbit.oak.plugins.index.lucene; + +import static com.google.common.collect.ImmutableList.of; +import static javax.jcr.PropertyType.TYPENAME_BINARY; +import static javax.jcr.PropertyType.TYPENAME_STRING; +import static org.apache.jackrabbit.JcrConstants.JCR_LASTMODIFIED; +import static org.apache.jackrabbit.JcrConstants.JCR_PRIMARYTYPE; +import static org.apache.jackrabbit.JcrConstants.NT_UNSTRUCTURED; +import static org.apache.jackrabbit.oak.api.Type.DATE; +import static org.apache.jackrabbit.oak.api.Type.STRINGS; +import static org.apache.jackrabbit.oak.plugins.index.lucene.LuceneIndexConstants.EXCLUDE_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.TYPE_LUCENE; + +import java.util.List; + +import org.apache.jackrabbit.oak.Oak; +import org.apache.jackrabbit.oak.api.ContentRepository; +import org.apache.jackrabbit.oak.api.Tree; +import org.apache.jackrabbit.oak.plugins.nodetype.write.InitialContent; +import org.apache.jackrabbit.oak.query.AbstractQueryTest; +import org.apache.jackrabbit.oak.spi.security.OpenSecurityProvider; +import org.junit.Test; + +/** + * Tests the {@link LuceneIndexProvider} exclusion settings + */ +public class LuceneIndexExclusionQueryTest extends AbstractQueryTest { + + private static final String NOT_IN = "notincluded"; + + @Override + protected void createTestIndexNode() throws Exception { + Tree lucene = createTestIndexNode(root.getTree("/"), TYPE_LUCENE); + lucene.setProperty(INCLUDE_PROPERTY_TYPES, + of(TYPENAME_BINARY, TYPENAME_STRING), STRINGS); + lucene.setProperty(EXCLUDE_PROPERTY_NAMES, of(NOT_IN), STRINGS); + root.commit(); + } + + @Override + protected ContentRepository createRepository() { + return new Oak().with(new InitialContent()) + .with(new OpenSecurityProvider()) + .with(new LowCostLuceneIndexProvider()) + .with(new LuceneIndexEditorProvider()) + .createContentRepository(); + } + + @Test + public void ignoreByType() throws Exception { + Tree content = root.getTree("/").addChild("content"); + Tree one = content.addChild("one"); + one.setProperty(JCR_PRIMARYTYPE, NT_UNSTRUCTURED); + one.setProperty(JCR_LASTMODIFIED, "2013-04-01T09:58:03.231Z", DATE); + one.setProperty("jcr:title", "abc"); + + Tree two = content.addChild("two"); + two.setProperty(JCR_PRIMARYTYPE, NT_UNSTRUCTURED); + two.setProperty(JCR_LASTMODIFIED, "2014-04-01T09:58:03.231Z", DATE); + two.setProperty("jcr:title", "abc"); + + root.commit(); + + String query = "/jcr:root/content//*[jcr:contains(., 'abc' )" + + " and (@" + JCR_LASTMODIFIED + + " > xs:dateTime('2014-04-01T08:58:03.231Z')) ]"; + assertQuery(query, "xpath", of("/content/two")); + } + + @Test + public void ignoreByName() throws Exception { + final List<String> expected = of("/content/two"); + + Tree content = root.getTree("/").addChild("content"); + Tree one = content.addChild("one"); + one.setProperty(JCR_PRIMARYTYPE, NT_UNSTRUCTURED); + one.setProperty("jcr:title", "abc"); + one.setProperty(NOT_IN, "azerty"); + + Tree two = content.addChild("two"); + two.setProperty(JCR_PRIMARYTYPE, NT_UNSTRUCTURED); + two.setProperty("jcr:title", "abc"); + two.setProperty(NOT_IN, "querty"); + + root.commit(); + + String query = "/jcr:root/content//*[jcr:contains(., 'abc' )" + + " and (@" + NOT_IN + " = 'querty') ]"; + assertQuery(query, "xpath", expected); + } + +} Propchange: jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexExclusionQueryTest.java ------------------------------------------------------------------------------ svn:mime-type = text/plain 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=1584132&r1=1584131&r2=1584132&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 Apr 2 19:04:22 2014 @@ -16,6 +16,7 @@ */ package org.apache.jackrabbit.oak.plugins.index.lucene; +import static javax.jcr.PropertyType.TYPENAME_STRING; import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertTrue; @@ -26,8 +27,6 @@ import static org.apache.jackrabbit.oak. 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 javax.jcr.PropertyType; - import org.apache.jackrabbit.oak.api.Type; import org.apache.jackrabbit.oak.plugins.index.IndexUpdateProvider; import org.apache.jackrabbit.oak.query.QueryEngineSettings; @@ -63,7 +62,8 @@ public class LuceneIndexTest { @Test public void testLucene() throws Exception { NodeBuilder index = builder.child(INDEX_DEFINITIONS_NAME); - newLuceneIndexDefinition(index, "lucene", null); + newLuceneIndexDefinition(index, "lucene", + ImmutableSet.of(TYPENAME_STRING)); NodeState before = builder.getNodeState(); builder.setProperty("foo", "bar"); @@ -85,7 +85,8 @@ public class LuceneIndexTest { @Test public void testLucene2() throws Exception { NodeBuilder index = builder.child(INDEX_DEFINITIONS_NAME); - newLuceneIndexDefinition(index, "lucene", null); + newLuceneIndexDefinition(index, "lucene", + ImmutableSet.of(TYPENAME_STRING)); NodeState before = builder.getNodeState(); builder.setProperty("foo", "bar"); @@ -116,7 +117,7 @@ public class LuceneIndexTest { public void testLucene3() throws Exception { NodeBuilder index = builder.child(INDEX_DEFINITIONS_NAME); newLuceneIndexDefinition(index, "lucene", - ImmutableSet.of(PropertyType.TYPENAME_STRING)); + ImmutableSet.of(TYPENAME_STRING)); NodeState before = builder.getNodeState(); builder.setProperty("foo", "bar");
