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 ca...@apache.org on 2015/12/22 17:27:59 UTC
svn commit: r1721424 - in /jackrabbit/oak/trunk/oak-lucene: ./
src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/
src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/spi/
src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/
Author: catholicon
Date: Tue Dec 22 16:27:58 2015
New Revision: 1721424
URL: http://svn.apache.org/viewvc?rev=1721424&view=rev
Log:
OAK-3576: Allow custom extension to augment indexed lucene documents
Added:
jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/IndexAugmentorFactory.java (with props)
jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/spi/FulltextQueryTermsProvider.java (with props)
jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/spi/IndexFieldProvider.java (with props)
jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/spi/package-info.java
- copied, changed from r1721341, jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/package-info.java
jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/IndexAugmentorFactoryTest.java (with props)
jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexAugmentTest.java (with props)
Modified:
jackrabbit/oak/trunk/oak-lucene/pom.xml
jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexEditor.java
jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexEditorContext.java
jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexEditorProvider.java
jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexProvider.java
jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexProviderService.java
jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LucenePropertyIndex.java
jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/package-info.java
Modified: jackrabbit/oak/trunk/oak-lucene/pom.xml
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/pom.xml?rev=1721424&r1=1721423&r2=1721424&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-lucene/pom.xml (original)
+++ jackrabbit/oak/trunk/oak-lucene/pom.xml Tue Dec 22 16:27:58 2015
@@ -112,6 +112,7 @@
org.apache.jackrabbit.oak.plugins.index.lucene,
org.apache.jackrabbit.oak.plugins.index.lucene.util,
org.apache.jackrabbit.oak.plugins.index.lucene.score,
+ org.apache.jackrabbit.oak.plugins.index.lucene.spi,
</Export-Package>
<_exportcontents>
org.apache.lucene.*;version=${lucene.version}
Added: jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/IndexAugmentorFactory.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/IndexAugmentorFactory.java?rev=1721424&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/IndexAugmentorFactory.java (added)
+++ jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/IndexAugmentorFactory.java Tue Dec 22 16:27:58 2015
@@ -0,0 +1,198 @@
+/*
+ * 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 com.google.common.collect.LinkedListMultimap;
+import com.google.common.collect.ListMultimap;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import org.apache.jackrabbit.oak.plugins.index.lucene.spi.FulltextQueryTermsProvider;
+import org.apache.jackrabbit.oak.plugins.index.lucene.spi.IndexFieldProvider;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+import org.apache.jackrabbit.oak.spi.whiteboard.Tracker;
+import org.apache.jackrabbit.oak.spi.whiteboard.Whiteboard;
+import org.apache.jackrabbit.oak.util.PerfLogger;
+import org.apache.lucene.analysis.Analyzer;
+import org.apache.lucene.document.Field;
+import org.apache.lucene.search.BooleanClause;
+import org.apache.lucene.search.BooleanQuery;
+import org.apache.lucene.search.Query;
+import org.slf4j.LoggerFactory;
+
+import javax.annotation.Nonnull;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+public class IndexAugmentorFactory {
+
+ private static final PerfLogger PERFLOG = new PerfLogger(
+ LoggerFactory.getLogger(IndexAugmentorFactory.class.getName() + ".perf"));
+
+ private final Tracker<IndexFieldProvider> indexFieldProviderTracker;
+ private final Tracker<FulltextQueryTermsProvider> fulltextQueryTermsProviderTracker;
+
+ private volatile Map<String, CompositeIndexFieldProvider> indexFieldProviderMap;
+ private volatile Map<String, CompositeFulltextQueryTermsProvider> fulltextQueryTermsProviderMap;
+
+ public IndexAugmentorFactory(Whiteboard whiteboard) {
+ indexFieldProviderTracker = whiteboard.track(IndexFieldProvider.class);
+ fulltextQueryTermsProviderTracker = whiteboard.track(FulltextQueryTermsProvider.class);
+
+ indexFieldProviderMap = Maps.newHashMap();
+ fulltextQueryTermsProviderMap = Maps.newHashMap();
+ }
+
+ @Nonnull
+ public IndexFieldProvider getIndexFieldProvider(String nodeType) {
+ IndexFieldProvider provider = indexFieldProviderMap.get(nodeType);
+ return (provider != null) ? provider : IndexFieldProvider.DEFAULT;
+ }
+
+ @Nonnull
+ public FulltextQueryTermsProvider getFulltextQueryTermsProvider(String nodeType) {
+ FulltextQueryTermsProvider provider = fulltextQueryTermsProviderMap.get(nodeType);
+ return (provider != null) ? provider : FulltextQueryTermsProvider.DEFAULT;
+ }
+
+ public void refreshServices() {
+ refreshIndexFieldProviderServices();
+ refreshFulltextQueryTermsProviderServices();
+ }
+
+ private void refreshIndexFieldProviderServices() {
+ ListMultimap<String, IndexFieldProvider> indexFieldProviderListMultimap =
+ LinkedListMultimap.create();
+ for (IndexFieldProvider provider : indexFieldProviderTracker.getServices()) {
+ Set<String> supportedNodeTypes = provider.getSupportedTypes();
+ for (String nodeType : supportedNodeTypes) {
+ indexFieldProviderListMultimap.put(nodeType, provider);
+ }
+ }
+
+ Map<String, CompositeIndexFieldProvider> tempMap = Maps.newHashMap();
+ for (String nodeType : indexFieldProviderListMultimap.keySet()) {
+ List<IndexFieldProvider> providers = indexFieldProviderListMultimap.get(nodeType);
+ CompositeIndexFieldProvider compositeIndexFieldProvider =
+ new CompositeIndexFieldProvider(nodeType, providers);
+ tempMap.put(nodeType, compositeIndexFieldProvider);
+ }
+
+ indexFieldProviderMap = tempMap;
+ }
+
+ private void refreshFulltextQueryTermsProviderServices() {
+ ListMultimap<String, FulltextQueryTermsProvider> fulltextQueryTermsProviderLinkedListMultimap =
+ LinkedListMultimap.create();
+ for (FulltextQueryTermsProvider provider : fulltextQueryTermsProviderTracker.getServices()) {
+ Set<String> supportedNodeTypes = provider.getSupportedTypes();
+ for (String nodeType : supportedNodeTypes) {
+ fulltextQueryTermsProviderLinkedListMultimap.put(nodeType, provider);
+ }
+ }
+
+ Map<String, CompositeFulltextQueryTermsProvider> tempMap = Maps.newHashMap();
+ for (String nodeType : fulltextQueryTermsProviderLinkedListMultimap.keySet()) {
+ List<FulltextQueryTermsProvider> providers = fulltextQueryTermsProviderLinkedListMultimap.get(nodeType);
+ CompositeFulltextQueryTermsProvider compositeFulltextQueryTermsProvider =
+ new CompositeFulltextQueryTermsProvider(nodeType, providers);
+ tempMap.put(nodeType, compositeFulltextQueryTermsProvider);
+ }
+
+ fulltextQueryTermsProviderMap = tempMap;
+ }
+
+ class CompositeIndexFieldProvider implements IndexFieldProvider {
+
+ private final String nodeType;
+ private final List<IndexFieldProvider> providers;
+
+ CompositeIndexFieldProvider(String nodeType, List<IndexFieldProvider> providers) {
+ this.nodeType = nodeType;
+ this.providers = providers;
+ }
+
+ @Nonnull
+ @Override
+ public List<Field> getAugmentedFields(final String path,
+ final NodeState document, final NodeState indexDefinition) {
+ List<Field> fields = Lists.newArrayList();
+ for (IndexFieldProvider indexFieldProvider : providers) {
+ final long start = PERFLOG.start();
+ Iterable<Field> providedFields = indexFieldProvider.getAugmentedFields(path, document, indexDefinition);
+ PERFLOG.end(start, 1, "indexFieldProvider: {}, path: {}, doc: {}, indexDef: {}",
+ indexFieldProvider, path, document, indexDefinition);
+ for (Field f : providedFields) {
+ fields.add(f);
+ }
+ }
+ return fields;
+ }
+
+ @Nonnull
+ @Override
+ public Set<String> getSupportedTypes() {
+ return Collections.singleton(nodeType);
+ }
+ }
+
+ class CompositeFulltextQueryTermsProvider implements FulltextQueryTermsProvider {
+
+ private final String nodeType;
+ private final List<FulltextQueryTermsProvider> providers;
+
+ CompositeFulltextQueryTermsProvider(String nodeType, List<FulltextQueryTermsProvider> providers) {
+ this.nodeType = nodeType;
+ this.providers = providers;
+ }
+
+ @Override
+ public Query getQueryTerm(final String text, final Analyzer analyzer) {
+ List<Query> subQueries = Lists.newArrayList();
+ for (FulltextQueryTermsProvider fulltextQueryTermsProvider : providers) {
+ final long start = PERFLOG.start();
+ Query subQuery = fulltextQueryTermsProvider.getQueryTerm(text, analyzer);
+ PERFLOG.end(start, 1, "fulltextQueryTermsProvider: {}, text: {}", fulltextQueryTermsProvider, text);
+ if (subQuery != null) {
+ subQueries.add(subQuery);
+ }
+ }
+
+ Query ret;
+ if (subQueries.size() == 0) {
+ ret = null;
+ } else if (subQueries.size() == 1) {
+ ret = subQueries.get(0);
+ } else {
+ BooleanQuery query = new BooleanQuery();
+ for ( Query subQuery : subQueries ) {
+ query.add(subQuery, BooleanClause.Occur.SHOULD);
+ }
+ ret = query;
+ }
+
+ return ret;
+ }
+
+ @Nonnull
+ @Override
+ public Set<String> getSupportedTypes() {
+ return Collections.singleton(nodeType);
+ }
+ }
+}
Propchange: jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/IndexAugmentorFactory.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexEditor.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexEditor.java?rev=1721424&r1=1721423&r2=1721424&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexEditor.java (original)
+++ jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexEditor.java Tue Dec 22 16:27:58 2015
@@ -42,6 +42,7 @@ import org.apache.jackrabbit.oak.plugins
import org.apache.jackrabbit.oak.plugins.index.fulltext.ExtractedText;
import org.apache.jackrabbit.oak.plugins.index.fulltext.ExtractedText.ExtractionResult;
import org.apache.jackrabbit.oak.plugins.index.lucene.Aggregate.Matcher;
+import org.apache.jackrabbit.oak.plugins.index.lucene.spi.IndexFieldProvider;
import org.apache.jackrabbit.oak.plugins.memory.EmptyNodeState;
import org.apache.jackrabbit.oak.plugins.tree.TreeFactory;
import org.apache.jackrabbit.oak.spi.commit.Editor;
@@ -122,12 +123,13 @@ public class LuceneIndexEditor implement
LuceneIndexEditor(NodeState root, NodeBuilder definition,
IndexUpdateCallback updateCallback,
@Nullable IndexCopier indexCopier,
- ExtractedTextCache extractedTextCache) throws CommitFailedException {
+ ExtractedTextCache extractedTextCache,
+ IndexAugmentorFactory augmentorFactory) throws CommitFailedException {
this.parent = null;
this.name = null;
this.path = "/";
this.context = new LuceneIndexEditorContext(root, definition,
- updateCallback, indexCopier, extractedTextCache);
+ updateCallback, indexCopier, extractedTextCache, augmentorFactory);
this.root = root;
this.isDeleted = false;
this.matcherState = MatcherState.NONE;
@@ -341,6 +343,8 @@ public class LuceneIndexEditor implement
dirty |= indexNullCheckEnabledProps(path, fields, state);
dirty |= indexNotNullCheckEnabledProps(path, fields, state);
+ dirty |= augmentCustomFields(path, fields, state);
+
// Check if a node having a single property was modified/deleted
if (!dirty) {
dirty = indexIfSinglePropertyRemoved();
@@ -452,14 +456,14 @@ public class LuceneIndexEditor implement
String pname,
PropertyDefinition pd) {
boolean includeTypeForFullText = indexingRule.includePropertyType(property.getType().tag());
+
+ boolean dirty = false;
if (Type.BINARY.tag() == property.getType().tag()
&& includeTypeForFullText) {
fields.addAll(newBinary(property, state, null, path + "@" + pname));
- return true;
- } else {
- boolean dirty = false;
-
- if (pd.propertyIndex && pd.includePropertyType(property.getType().tag())){
+ dirty = true;
+ } else {
+ if (pd.propertyIndex && pd.includePropertyType(property.getType().tag())) {
dirty |= addTypedFields(fields, property, pname);
}
@@ -489,8 +493,9 @@ public class LuceneIndexEditor implement
dirty |= addFacetFields(fields, property, pname, pd);
}
- return dirty;
}
+
+ return dirty;
}
private String constructAnalyzedPropertyName(String pname) {
@@ -627,6 +632,26 @@ public class LuceneIndexEditor implement
return fields;
}
+ private boolean augmentCustomFields(final String path, final List<Field> fields,
+ final NodeState document) {
+ boolean dirty = false;
+
+ IndexAugmentorFactory augmentorFactory = context.getAugmentorFactory();
+ if (augmentorFactory != null) {
+ IndexDefinition defn = getDefinition();
+ Iterable<Field> augmentedFields = augmentorFactory
+ .getIndexFieldProvider(indexingRule.getNodeTypeName())
+ .getAugmentedFields(path, document, defn.getDefinitionNodeState());
+
+ for (Field field : augmentedFields) {
+ fields.add(field);
+ dirty = true;
+ }
+ }
+
+ return dirty;
+ }
+
//~-------------------------------------------------------< NullCheck Support >
private boolean indexNotNullCheckEnabledProps(String path, List<Field> fields, NodeState state) {
@@ -765,7 +790,6 @@ public class LuceneIndexEditor implement
});
return dirtyFlag.get();
}
-
/**
* Create the fulltext field from the aggregated nodes. If result is for aggregate for a relative node
* include then
Modified: jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexEditorContext.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexEditorContext.java?rev=1721424&r1=1721423&r2=1721424&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexEditorContext.java (original)
+++ jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexEditorContext.java Tue Dec 22 16:27:58 2015
@@ -147,19 +147,23 @@ public class LuceneIndexEditorContext {
private final TextExtractionStats textExtractionStats = new TextExtractionStats();
private final ExtractedTextCache extractedTextCache;
+
+ private final IndexAugmentorFactory augmentorFactory;
/**
* The media types supported by the parser used.
*/
private Set<MediaType> supportedMediaTypes;
LuceneIndexEditorContext(NodeState root, NodeBuilder definition, IndexUpdateCallback updateCallback,
- @Nullable IndexCopier indexCopier, ExtractedTextCache extractedTextCache) {
+ @Nullable IndexCopier indexCopier, ExtractedTextCache extractedTextCache,
+ IndexAugmentorFactory augmentorFactory) {
this.definitionBuilder = definition;
this.indexCopier = indexCopier;
this.definition = new IndexDefinition(root, definition);
this.indexedNodes = 0;
this.updateCallback = updateCallback;
this.extractedTextCache = extractedTextCache;
+ this.augmentorFactory = augmentorFactory;
if (this.definition.isOfOldFormat()){
IndexDefinition.updateDefinition(definition);
}
@@ -349,6 +353,10 @@ public class LuceneIndexEditorContext {
return extractedTextCache;
}
+ IndexAugmentorFactory getAugmentorFactory() {
+ return augmentorFactory;
+ }
+
public boolean isReindex() {
return reindex;
}
Modified: jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexEditorProvider.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexEditorProvider.java?rev=1721424&r1=1721423&r2=1721424&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexEditorProvider.java (original)
+++ jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexEditorProvider.java Tue Dec 22 16:27:58 2015
@@ -39,6 +39,7 @@ import static org.apache.jackrabbit.oak.
public class LuceneIndexEditorProvider implements IndexEditorProvider {
private final IndexCopier indexCopier;
private final ExtractedTextCache extractedTextCache;
+ private final IndexAugmentorFactory augmentorFactory;
public LuceneIndexEditorProvider() {
this(null);
@@ -51,8 +52,15 @@ public class LuceneIndexEditorProvider i
public LuceneIndexEditorProvider(@Nullable IndexCopier indexCopier,
ExtractedTextCache extractedTextCache) {
+ this(indexCopier, extractedTextCache, null);
+ }
+
+ public LuceneIndexEditorProvider(@Nullable IndexCopier indexCopier,
+ ExtractedTextCache extractedTextCache,
+ IndexAugmentorFactory augmentorFactory) {
this.indexCopier = indexCopier;
this.extractedTextCache = extractedTextCache;
+ this.augmentorFactory = augmentorFactory;
}
@Override
@@ -61,7 +69,7 @@ public class LuceneIndexEditorProvider i
@Nonnull IndexUpdateCallback callback)
throws CommitFailedException {
if (TYPE_LUCENE.equals(type)) {
- return new LuceneIndexEditor(root, definition, callback, indexCopier, extractedTextCache);
+ return new LuceneIndexEditor(root, definition, callback, indexCopier, extractedTextCache, augmentorFactory);
}
return null;
}
Modified: jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexProvider.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexProvider.java?rev=1721424&r1=1721423&r2=1721424&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexProvider.java (original)
+++ jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexProvider.java Tue Dec 22 16:27:58 2015
@@ -45,21 +45,24 @@ public class LuceneIndexProvider impleme
ScorerProviderFactory scorerFactory;
+ IndexAugmentorFactory augmentorFactory;
+
public LuceneIndexProvider() {
this(new IndexTracker());
}
public LuceneIndexProvider(IndexCopier indexCopier) {
- this(new IndexTracker(indexCopier), ScorerProviderFactory.DEFAULT);
+ this(new IndexTracker(indexCopier));
}
public LuceneIndexProvider(IndexTracker tracker) {
- this(tracker, ScorerProviderFactory.DEFAULT);
+ this(tracker, ScorerProviderFactory.DEFAULT, null);
}
- public LuceneIndexProvider(IndexTracker tracker, ScorerProviderFactory scorerFactory) {
+ public LuceneIndexProvider(IndexTracker tracker, ScorerProviderFactory scorerFactory, IndexAugmentorFactory augmentorFactory) {
this.tracker = tracker;
this.scorerFactory = scorerFactory;
+ this.augmentorFactory = augmentorFactory;
}
public void close() {
@@ -85,7 +88,7 @@ public class LuceneIndexProvider impleme
}
protected LucenePropertyIndex newLucenePropertyIndex() {
- return new LucenePropertyIndex(tracker, scorerFactory);
+ return new LucenePropertyIndex(tracker, scorerFactory, augmentorFactory);
}
/**
Modified: jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexProviderService.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexProviderService.java?rev=1721424&r1=1721423&r2=1721424&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexProviderService.java (original)
+++ jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexProviderService.java Tue Dec 22 16:27:58 2015
@@ -45,6 +45,7 @@ import org.apache.felix.scr.annotations.
import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.apache.felix.scr.annotations.ReferencePolicy;
import org.apache.felix.scr.annotations.ReferencePolicyOption;
+import org.apache.felix.scr.annotations.References;
import org.apache.jackrabbit.oak.api.jmx.CacheStatsMBean;
import org.apache.jackrabbit.oak.cache.CacheStats;
import org.apache.jackrabbit.oak.commons.PropertiesUtil;
@@ -52,6 +53,8 @@ import org.apache.jackrabbit.oak.osgi.Os
import org.apache.jackrabbit.oak.plugins.index.IndexEditorProvider;
import org.apache.jackrabbit.oak.plugins.index.aggregate.NodeAggregator;
import org.apache.jackrabbit.oak.plugins.index.fulltext.PreExtractedTextProvider;
+import org.apache.jackrabbit.oak.plugins.index.lucene.spi.FulltextQueryTermsProvider;
+import org.apache.jackrabbit.oak.plugins.index.lucene.spi.IndexFieldProvider;
import org.apache.jackrabbit.oak.spi.commit.BackgroundObserver;
import org.apache.jackrabbit.oak.plugins.index.lucene.score.ScorerProviderFactory;
import org.apache.jackrabbit.oak.spi.commit.BackgroundObserverMBean;
@@ -74,6 +77,20 @@ import static org.apache.jackrabbit.oak.
@SuppressWarnings("UnusedDeclaration")
@Component(metatype = true, label = "Apache Jackrabbit Oak LuceneIndexProvider")
+@References({
+ @Reference(name = "IndexFieldProvider",
+ policy = ReferencePolicy.DYNAMIC,
+ cardinality = ReferenceCardinality.OPTIONAL_MULTIPLE,
+ referenceInterface = IndexFieldProvider.class,
+ bind = "indexFieldProviderServiceUpdated",
+ unbind = "indexFieldProviderServiceUpdated"),
+ @Reference(name = "FulltextQueryTermsProvider",
+ policy = ReferencePolicy.DYNAMIC,
+ cardinality = ReferenceCardinality.OPTIONAL_MULTIPLE,
+ referenceInterface = FulltextQueryTermsProvider.class,
+ bind = "indexFulltextQueryTermsProviderServiceUpdated",
+ unbind = "indexFulltextQueryTermsProviderServiceUpdated")
+})
public class LuceneIndexProviderService {
public static final String REPOSITORY_HOME = "repository.home";
@@ -177,6 +194,8 @@ public class LuceneIndexProviderService
@Reference
ScorerProviderFactory scorerFactory;
+ private IndexAugmentorFactory augmentorFactory;
+
@Reference(policy = ReferencePolicy.DYNAMIC,
cardinality = ReferenceCardinality.OPTIONAL_MULTIPLE,
policyOption = ReferencePolicyOption.GREEDY
@@ -207,7 +226,8 @@ public class LuceneIndexProviderService
whiteboard = new OsgiWhiteboard(bundleContext);
threadPoolSize = PropertiesUtil.toInteger(config.get(PROP_THREAD_POOL_SIZE), PROP_THREAD_POOL_SIZE_DEFAULT);
initializeExtractedTextCache(bundleContext, config);
- indexProvider = new LuceneIndexProvider(createTracker(bundleContext, config), scorerFactory);
+ augmentorFactory = new IndexAugmentorFactory(whiteboard);
+ indexProvider = new LuceneIndexProvider(createTracker(bundleContext, config), scorerFactory, augmentorFactory);
initializeLogging(config);
initialize();
@@ -288,10 +308,10 @@ public class LuceneIndexProviderService
LuceneIndexEditorProvider editorProvider;
if (enableCopyOnWrite){
initializeIndexCopier(bundleContext, config);
- editorProvider = new LuceneIndexEditorProvider(indexCopier, extractedTextCache);
+ editorProvider = new LuceneIndexEditorProvider(indexCopier, extractedTextCache, augmentorFactory);
log.info("Enabling CopyOnWrite support. Index files would be copied under {}", indexDir.getAbsolutePath());
} else {
- editorProvider = new LuceneIndexEditorProvider(null, extractedTextCache);
+ editorProvider = new LuceneIndexEditorProvider(null, extractedTextCache, augmentorFactory);
}
regs.add(bundleContext.registerService(IndexEditorProvider.class.getName(), editorProvider, null));
oakRegs.add(registerMBean(whiteboard,
@@ -471,4 +491,11 @@ public class LuceneIndexProviderService
registerExtractedTextProvider(null);
}
+ private void indexFieldProviderServiceUpdated(IndexFieldProvider indexFieldProvider) {
+ augmentorFactory.refreshServices();
+ }
+
+ private void indexFulltextQueryTermsProviderServiceUpdated(FulltextQueryTermsProvider fulltextQueryTermsProvider) {
+ augmentorFactory.refreshServices();
+ }
}
Modified: jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LucenePropertyIndex.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LucenePropertyIndex.java?rev=1721424&r1=1721423&r2=1721424&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LucenePropertyIndex.java (original)
+++ jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LucenePropertyIndex.java Tue Dec 22 16:27:58 2015
@@ -47,6 +47,7 @@ import org.apache.jackrabbit.oak.plugins
import org.apache.jackrabbit.oak.plugins.index.lucene.IndexDefinition.IndexingRule;
import org.apache.jackrabbit.oak.plugins.index.lucene.IndexPlanner.PlanResult;
import org.apache.jackrabbit.oak.plugins.index.lucene.score.ScorerProviderFactory;
+import org.apache.jackrabbit.oak.plugins.index.lucene.spi.FulltextQueryTermsProvider;
import org.apache.jackrabbit.oak.plugins.index.lucene.util.FacetHelper;
import org.apache.jackrabbit.oak.plugins.index.lucene.util.MoreLikeThisHelper;
import org.apache.jackrabbit.oak.plugins.index.lucene.util.SpellcheckHelper;
@@ -208,14 +209,20 @@ public class LucenePropertyIndex impleme
private final Highlighter highlighter = new Highlighter(new SimpleHTMLFormatter("<strong>", "</strong>"),
new SimpleHTMLEncoder(), null);
+ private final IndexAugmentorFactory augmentorFactory;
+
public LucenePropertyIndex(IndexTracker tracker) {
- this.tracker = tracker;
- this.scorerProviderFactory = ScorerProviderFactory.DEFAULT;
+ this(tracker, ScorerProviderFactory.DEFAULT);
}
public LucenePropertyIndex(IndexTracker tracker, ScorerProviderFactory factory) {
+ this(tracker, factory, null);
+ }
+
+ public LucenePropertyIndex(IndexTracker tracker, ScorerProviderFactory factory, IndexAugmentorFactory augmentorFactory) {
this.tracker = tracker;
this.scorerProviderFactory = factory;
+ this.augmentorFactory = augmentorFactory;
}
@Override
@@ -275,7 +282,7 @@ public class LucenePropertyIndex impleme
.append("(")
.append(path)
.append(") ");
- sb.append(getLuceneRequest(plan, null));
+ sb.append(getLuceneRequest(plan, augmentorFactory, null));
if (plan.getSortOrder() != null && !plan.getSortOrder().isEmpty()) {
sb.append(" ordering:").append(plan.getSortOrder());
}
@@ -366,7 +373,7 @@ public class LucenePropertyIndex impleme
checkState(indexNode != null);
try {
IndexSearcher searcher = indexNode.getSearcher();
- LuceneRequestFacade luceneRequestFacade = getLuceneRequest(plan, searcher.getIndexReader());
+ LuceneRequestFacade luceneRequestFacade = getLuceneRequest(plan, augmentorFactory, searcher.getIndexReader());
if (luceneRequestFacade.getLuceneRequest() instanceof Query) {
Query query = (Query) luceneRequestFacade.getLuceneRequest();
@@ -514,7 +521,7 @@ public class LucenePropertyIndex impleme
checkState(indexNode != null);
try {
IndexSearcher searcher = indexNode.getSearcher();
- LuceneRequestFacade luceneRequestFacade = getLuceneRequest(plan, searcher.getIndexReader());
+ LuceneRequestFacade luceneRequestFacade = getLuceneRequest(plan, augmentorFactory, searcher.getIndexReader());
if (luceneRequestFacade.getLuceneRequest() instanceof Query) {
Query query = (Query) luceneRequestFacade.getLuceneRequest();
TotalHitCountCollector collector = new TotalHitCountCollector();
@@ -649,7 +656,8 @@ public class LucenePropertyIndex impleme
* @param reader the Lucene reader
* @return the Lucene query
*/
- private static LuceneRequestFacade getLuceneRequest(IndexPlan plan, IndexReader reader) {
+ private static LuceneRequestFacade getLuceneRequest(IndexPlan plan, IndexAugmentorFactory augmentorFactory, IndexReader reader) {
+ FulltextQueryTermsProvider augmentor = getIndexAgumentor(plan, augmentorFactory);
List<Query> qs = new ArrayList<Query>();
Filter filter = plan.getFilter();
FullTextExpression ft = filter.getFullTextConstraint();
@@ -661,7 +669,7 @@ public class LucenePropertyIndex impleme
// when using the LowCostLuceneIndexProvider
// which is used for testing
} else {
- qs.add(getFullTextQuery(plan, ft, analyzer));
+ qs.add(getFullTextQuery(plan, ft, analyzer, augmentor));
}
@@ -815,6 +823,16 @@ public class LucenePropertyIndex impleme
}
return null;
}
+ private static FulltextQueryTermsProvider getIndexAgumentor(IndexPlan plan, IndexAugmentorFactory augmentorFactory) {
+ PlanResult planResult = getPlanResult(plan);
+ IndexDefinition defn = planResult.indexDefinition;
+
+ if (augmentorFactory != null && defn.getVersion().isAtLeast(IndexFormatVersion.V2)){
+ return augmentorFactory.getFulltextQueryTermsProvider(getPlanResult(plan).indexingRule.getNodeTypeName());
+ }
+
+ return null;
+ }
private static void addNonFullTextConstraints(List<Query> qs,
IndexPlan plan, IndexReader reader) {
@@ -1161,7 +1179,7 @@ public class LucenePropertyIndex impleme
}
static Query getFullTextQuery(final IndexPlan plan, FullTextExpression ft,
- final Analyzer analyzer) {
+ final Analyzer analyzer, final FulltextQueryTermsProvider augmentor) {
final PlanResult pr = getPlanResult(plan);
// a reference to the query, so it can be set in the visitor
// (a "non-local return")
@@ -1178,7 +1196,7 @@ public class LucenePropertyIndex impleme
public boolean visit(FullTextOr or) {
BooleanQuery q = new BooleanQuery();
for (FullTextExpression e : or.list) {
- Query x = getFullTextQuery(plan, e, analyzer);
+ Query x = getFullTextQuery(plan, e, analyzer, augmentor);
q.add(x, SHOULD);
}
result.set(q);
@@ -1189,7 +1207,7 @@ public class LucenePropertyIndex impleme
public boolean visit(FullTextAnd and) {
BooleanQuery q = new BooleanQuery();
for (FullTextExpression e : and.list) {
- Query x = getFullTextQuery(plan, e, analyzer);
+ Query x = getFullTextQuery(plan, e, analyzer, augmentor);
/* Only unwrap the clause if MUST_NOT(x) */
boolean hasMustNot = false;
if (x instanceof BooleanQuery) {
@@ -1216,7 +1234,7 @@ public class LucenePropertyIndex impleme
private boolean visitTerm(String propertyName, String text, String boost, boolean not) {
String p = getLuceneFieldName(propertyName, pr);
- Query q = tokenToQuery(text, p, pr.indexingRule, analyzer);
+ Query q = tokenToQuery(text, p, pr.indexingRule, analyzer, augmentor);
if (q == null) {
return false;
}
@@ -1262,7 +1280,8 @@ public class LucenePropertyIndex impleme
return p;
}
- private static Query tokenToQuery(String text, String fieldName, IndexingRule indexingRule, Analyzer analyzer) {
+ private static Query tokenToQuery(String text, String fieldName, IndexingRule indexingRule, Analyzer analyzer, FulltextQueryTermsProvider augmentor) {
+ Query ret;
//Expand the query on fulltext field
if (FieldNames.FULLTEXT.equals(fieldName) &&
!indexingRule.getNodeScopeAnalyzedProps().isEmpty()) {
@@ -1276,9 +1295,25 @@ public class LucenePropertyIndex impleme
//Add the query for actual fulltext field also. That query would
//not be boosted
in.add(tokenToQuery(text, fieldName, analyzer), BooleanClause.Occur.SHOULD);
- return in;
+ ret = in;
+ } else {
+ ret = tokenToQuery(text, fieldName, analyzer);
}
- return tokenToQuery(text, fieldName, analyzer);
+
+ //Augment query terms if available (as a 'SHOULD' clause)
+ if (augmentor != null && FieldNames.FULLTEXT.equals(fieldName)) {
+ Query subQuery = augmentor.getQueryTerm(text, analyzer);
+ if (subQuery != null) {
+ BooleanQuery query = new BooleanQuery();
+
+ query.add(ret, BooleanClause.Occur.SHOULD);
+ query.add(subQuery, BooleanClause.Occur.SHOULD);
+
+ ret = query;
+ }
+ }
+
+ return ret;
}
static Query tokenToQuery(String text, String fieldName, Analyzer analyzer) {
Modified: jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/package-info.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/package-info.java?rev=1721424&r1=1721423&r2=1721424&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/package-info.java (original)
+++ jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/package-info.java Tue Dec 22 16:27:58 2015
@@ -14,9 +14,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-@Version("2.9.0")
+@Version("3.0.0")
@Export(optional = "provide:=true")
package org.apache.jackrabbit.oak.plugins.index.lucene;
import aQute.bnd.annotation.Version;
-import aQute.bnd.annotation.Export;
\ No newline at end of file
+import aQute.bnd.annotation.Export;
Added: jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/spi/FulltextQueryTermsProvider.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/spi/FulltextQueryTermsProvider.java?rev=1721424&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/spi/FulltextQueryTermsProvider.java (added)
+++ jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/spi/FulltextQueryTermsProvider.java Tue Dec 22 16:27:58 2015
@@ -0,0 +1,62 @@
+/*
+ * 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.spi;
+
+import org.apache.lucene.analysis.Analyzer;
+import org.apache.lucene.search.Query;
+
+import javax.annotation.Nonnull;
+import java.util.Collections;
+import java.util.Set;
+
+/**
+ * Implementations of this interface would get callbacks while forming lucene full text queries.
+ */
+public interface FulltextQueryTermsProvider {
+ /**
+ * Implementation which doesn't do anything useful... yet, abides with the contract.
+ */
+ FulltextQueryTermsProvider DEFAULT = new FulltextQueryTermsProvider() {
+ @Override
+ public Query getQueryTerm(String text, Analyzer analyzer) {
+ return null;
+ }
+
+ @Override
+ public Set<String> getSupportedTypes() {
+ return Collections.EMPTY_SET;
+ }
+ };
+ /**
+ * This method would get called while forming full text clause for full text clause not constrained on a particular
+ * field.
+ * @param text full text term
+ * @param analyzer {@link Analyzer} being used while forming the query. Can be used to analyze text consistently.
+ * @return {@link Query} object to be OR'ed with query being prepared. {@code null}, if nothing is to be added.
+ */
+ Query getQueryTerm(String text, Analyzer analyzer);
+
+ /**
+ * This method is used to find which node types are supported by the implementation. Based, on the index
+ * definition being used to query the document, only those implementations would get callback to
+ * {@link FulltextQueryTermsProvider#getQueryTerm} which declare a matching node type. Note, node types are
+ * exact matches and do not support inheritance.
+ * @return {@link Set} of types supported by the implementation
+ */
+ @Nonnull
+ Set<String> getSupportedTypes();
+}
Propchange: jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/spi/FulltextQueryTermsProvider.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/spi/IndexFieldProvider.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/spi/IndexFieldProvider.java?rev=1721424&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/spi/IndexFieldProvider.java (added)
+++ jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/spi/IndexFieldProvider.java Tue Dec 22 16:27:58 2015
@@ -0,0 +1,66 @@
+/*
+ * 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.spi;
+
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+import org.apache.lucene.document.Field;
+
+import javax.annotation.Nonnull;
+import java.util.Collections;
+import java.util.Set;
+
+/**
+ * Implementations of this interface would get callbacks while indexing documents. It's the responsibility
+ * of the implementation to exit as early as possible if it doesn't care about the document being indexed.
+ */
+public interface IndexFieldProvider {
+ /**
+ * Implementation which doesn't do anything useful... yet, abides with the contract.
+ */
+ IndexFieldProvider DEFAULT = new IndexFieldProvider() {
+ @Override
+ public Iterable<Field> getAugmentedFields(String path, NodeState document, NodeState indexDefinition) {
+ return Collections.EMPTY_LIST;
+ }
+
+ @Override
+ public Set<String> getSupportedTypes() {
+ return Collections.EMPTY_SET;
+ }
+ };
+
+ /**
+ * This method would get called while indexing a document.
+ *
+ * @param path path of the document being indexed
+ * @param document {@link NodeState} of the document being indexed
+ * @param indexDefinition {@link NodeState} of index definition
+ * @return {@link Iterable} of fields that are to be added to {@link org.apache.lucene.document.Document} being prepared
+ */
+ @Nonnull
+ Iterable<Field> getAugmentedFields(String path, NodeState document, NodeState indexDefinition);
+
+ /**
+ * This method is used to find which node types are supported by the implementation. Based, on the index
+ * definition being used to index the document, only those implementations would get callback to
+ * {@link IndexFieldProvider#getAugmentedFields} which declare a matching node type. Note, node types are
+ * exact matches and do not support inheritance.
+ * @return {@link Set} of types supported by the implementation
+ */
+ @Nonnull
+ Set<String> getSupportedTypes();
+}
Propchange: jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/spi/IndexFieldProvider.java
------------------------------------------------------------------------------
svn:eol-style = native
Copied: jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/spi/package-info.java (from r1721341, jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/package-info.java)
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/spi/package-info.java?p2=jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/spi/package-info.java&p1=jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/package-info.java&r1=1721341&r2=1721424&rev=1721424&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/package-info.java (original)
+++ jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/spi/package-info.java Tue Dec 22 16:27:58 2015
@@ -14,9 +14,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-@Version("2.9.0")
+@Version("1.0.0")
@Export(optional = "provide:=true")
-package org.apache.jackrabbit.oak.plugins.index.lucene;
+package org.apache.jackrabbit.oak.plugins.index.lucene.spi;
+import aQute.bnd.annotation.Export;
import aQute.bnd.annotation.Version;
-import aQute.bnd.annotation.Export;
\ No newline at end of file
Added: jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/IndexAugmentorFactoryTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/IndexAugmentorFactoryTest.java?rev=1721424&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/IndexAugmentorFactoryTest.java (added)
+++ jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/IndexAugmentorFactoryTest.java Tue Dec 22 16:27:58 2015
@@ -0,0 +1,185 @@
+/*
+ * 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 com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+import org.apache.jackrabbit.oak.plugins.index.lucene.spi.FulltextQueryTermsProvider;
+import org.apache.jackrabbit.oak.plugins.index.lucene.spi.IndexFieldProvider;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+import org.apache.jackrabbit.oak.spi.whiteboard.DefaultWhiteboard;
+import org.apache.jackrabbit.oak.spi.whiteboard.Whiteboard;
+import org.apache.lucene.analysis.Analyzer;
+import org.apache.lucene.document.Field;
+import org.apache.lucene.document.StringField;
+import org.apache.lucene.index.Term;
+import org.apache.lucene.search.BooleanClause;
+import org.apache.lucene.search.BooleanQuery;
+import org.apache.lucene.search.Query;
+import org.apache.lucene.search.TermQuery;
+import org.hamcrest.CoreMatchers;
+import org.junit.Before;
+import org.junit.Test;
+
+import javax.annotation.Nonnull;
+import java.util.List;
+import java.util.Set;
+
+import static org.apache.lucene.search.BooleanClause.Occur.SHOULD;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+
+public class IndexAugmentorFactoryTest {
+ private IndexAugmentorFactory indexAugmentorFactory;
+ private Whiteboard whiteboard = new DefaultWhiteboard();
+
+ @Before
+ public void initializeFactory() {
+ indexAugmentorFactory = new IndexAugmentorFactory(whiteboard);
+ }
+
+ @Test
+ public void compositeIndexProvider()
+ {
+ final String typeA = "type:A";
+ final String typeB = "type:B";
+ final String typeC = "type:C";
+ final String typeD = "type:D";
+
+ new IdentifiableIndexFiledProvider("1", Sets.newHashSet(typeA, typeB));
+ new IdentifiableIndexFiledProvider("2", Sets.newHashSet(typeC));
+ new IdentifiableIndexFiledProvider("3", Sets.newHashSet(typeA, typeB));
+
+ indexAugmentorFactory.refreshServices();
+
+ validateComposedFields(typeA, "1", "3");
+ validateComposedFields(typeC, "2");
+ validateComposedFields(typeD);
+ }
+
+ @Test
+ public void compositeQueryTermsProvider()
+ {
+ final String typeA = "type:A";
+ final String typeB = "type:B";
+ final String typeC = "type:C";
+ final String typeD = "type:D";
+ final String typeE = "type:E";
+
+ new IdentifiableQueryTermsProvider("1", Sets.newHashSet(typeA, typeB));
+ new IdentifiableQueryTermsProvider("2", Sets.newHashSet(typeC));
+ new IdentifiableQueryTermsProvider("3", Sets.newHashSet(typeA, typeB));
+ new IdentifiableQueryTermsProvider(null, Sets.newHashSet(typeE));
+
+ indexAugmentorFactory.refreshServices();
+
+ validateComposedQueryTerms(typeA, "1", "3");
+ validateComposedQueryTerms(typeC, "2");
+ validateComposedQueryTerms(typeD);
+ validateComposedQueryTerms(typeE);
+ }
+
+ void validateComposedFields(String type, String ... expected) {
+ IndexFieldProvider compositeIndexProvider = indexAugmentorFactory.getIndexFieldProvider(type);
+ Iterable<Field> fields = compositeIndexProvider.getAugmentedFields(null, null, null);
+ Set<String> ids = Sets.newHashSet();
+ for (Field f : fields) {
+ ids.add(f.stringValue());
+ }
+
+ assertEquals(expected.length, Iterables.size(ids));
+ assertThat(ids, CoreMatchers.hasItems(expected));
+ }
+
+ void validateComposedQueryTerms(String type, String ... expected) {
+ FulltextQueryTermsProvider compositeQueryTermsProvider = indexAugmentorFactory.getFulltextQueryTermsProvider(type);
+ Query q = compositeQueryTermsProvider.getQueryTerm(null, null);
+ if (q == null) {
+ assertEquals("No query terms generated for " + type + ".", 0, expected.length);
+ } else {
+ Set<String> ids = Sets.newHashSet();
+ if (q instanceof BooleanQuery) {
+ BooleanQuery query = (BooleanQuery) q;
+ List<BooleanClause> clauses = query.clauses();
+ for (BooleanClause clause : clauses) {
+ assertEquals(SHOULD, clause.getOccur());
+
+ Query subQuery = clause.getQuery();
+ String subQueryStr = subQuery.toString();
+ ids.add(subQueryStr.substring(0, subQueryStr.indexOf(":1")));
+ }
+ } else {
+ String subQueryStr = q.toString();
+ ids.add(subQueryStr.substring(0, subQueryStr.indexOf(":1")));
+ }
+
+ assertEquals(expected.length, Iterables.size(ids));
+ assertThat(ids, CoreMatchers.hasItems(expected));
+ }
+ }
+
+ class IdentifiableIndexFiledProvider implements IndexFieldProvider {
+ private final Field id;
+ private final Set<String> nodeTypes;
+
+ IdentifiableIndexFiledProvider(String id, Set<String> nodeTypes) {
+ this.id = new StringField("id", id, Field.Store.NO);
+ this.nodeTypes = nodeTypes;
+
+ whiteboard.register(IndexFieldProvider.class, this, null);
+ }
+
+ @Nonnull
+ @Override
+ public Iterable<Field> getAugmentedFields(String path, NodeState document, NodeState indexDefinition) {
+ return Lists.newArrayList(id);
+ }
+
+ @Nonnull
+ @Override
+ public Set<String> getSupportedTypes() {
+ return nodeTypes;
+ }
+ }
+
+ class IdentifiableQueryTermsProvider implements FulltextQueryTermsProvider {
+ private final Query id;
+ private final Set<String> nodeTypes;
+
+ IdentifiableQueryTermsProvider(String id, Set<String> nodeTypes) {
+ this.id = (id == null)?null:new TermQuery(new Term(id, "1"));
+ this.nodeTypes = nodeTypes;
+
+ whiteboard.register(FulltextQueryTermsProvider.class, this, null);
+ }
+
+ @Override
+ public Query getQueryTerm(String text, Analyzer analyzer) {
+ return id;
+ }
+
+ @Nonnull
+ @Override
+ public Set<String> getSupportedTypes() {
+ return nodeTypes;
+ }
+ }
+}
Propchange: jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/IndexAugmentorFactoryTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexAugmentTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexAugmentTest.java?rev=1721424&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexAugmentTest.java (added)
+++ jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexAugmentTest.java Tue Dec 22 16:27:58 2015
@@ -0,0 +1,703 @@
+/*
+ * 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 com.google.common.collect.Lists;
+import org.apache.commons.io.IOUtils;
+import org.apache.jackrabbit.JcrConstants;
+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.api.Type;
+import org.apache.jackrabbit.oak.plugins.index.IndexConstants;
+import org.apache.jackrabbit.oak.plugins.index.lucene.score.ScorerProviderFactory;
+import org.apache.jackrabbit.oak.plugins.index.lucene.spi.FulltextQueryTermsProvider;
+import org.apache.jackrabbit.oak.plugins.index.lucene.spi.IndexFieldProvider;
+import org.apache.jackrabbit.oak.plugins.nodetype.write.NodeTypeRegistry;
+import org.apache.jackrabbit.oak.query.AbstractQueryTest;
+import org.apache.jackrabbit.oak.spi.commit.Observer;
+import org.apache.jackrabbit.oak.spi.query.QueryIndexProvider;
+import org.apache.jackrabbit.oak.spi.security.OpenSecurityProvider;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+import org.apache.jackrabbit.oak.spi.whiteboard.DefaultWhiteboard;
+import org.apache.jackrabbit.oak.spi.whiteboard.Whiteboard;
+import org.apache.lucene.analysis.Analyzer;
+import org.apache.lucene.document.Document;
+import org.apache.lucene.document.Field;
+import org.apache.lucene.document.StringField;
+import org.apache.lucene.index.Term;
+import org.apache.lucene.search.IndexSearcher;
+import org.apache.lucene.search.Query;
+import org.apache.lucene.search.ScoreDoc;
+import org.apache.lucene.search.TermQuery;
+import org.apache.lucene.search.TopDocs;
+import org.junit.Test;
+
+import javax.annotation.Nonnull;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+public class LuceneIndexAugmentTest extends AbstractQueryTest {
+ private final SimpleIndexAugmentorFactory factory = new SimpleIndexAugmentorFactory();
+
+ private IndexTracker tracker = new IndexTracker();
+
+ private IndexNode indexNode;
+
+ @Override
+ protected void createTestIndexNode() throws Exception {
+ setTraversalEnabled(false);
+ }
+
+ @Override
+ protected ContentRepository createRepository() {
+ LuceneIndexEditorProvider editorProvider = new LuceneIndexEditorProvider(null,
+ new ExtractedTextCache(0, 0),
+ factory);
+ LuceneIndexProvider provider = new LuceneIndexProvider(tracker,
+ ScorerProviderFactory.DEFAULT,
+ factory);
+ return new Oak()
+ .with(new OpenSecurityProvider())
+ .with((QueryIndexProvider) provider)
+ .with((Observer) provider)
+ .with(editorProvider)
+ .createContentRepository();
+ }
+
+ //OAK-3576
+ @Test public void queryHook() throws Exception {
+ //setup repo and index
+ NodeTypeRegistry.register(root, IOUtils.toInputStream(TestUtil.TEST_NODE_TYPE), "test nodeType");
+ Tree props = createIndex(TestUtil.NT_TEST);
+ TestUtil.enableForFullText(props, "foo");
+ root.commit();
+
+ //setup query augmentor
+ final String testSearchText = "search this text";
+ final String realSearchText = "bar";
+ factory.fulltextQueryTermsProvider = new FulltextQueryTermsProvider() {
+ @Override
+ public Query getQueryTerm(String text, Analyzer analyzer) {
+ assertEquals("Full text term passed to provider isn't same as the one passed in query",
+ testSearchText, text);
+ return new TermQuery(new Term(":fulltext", realSearchText));
+ }
+
+ @Nonnull
+ @Override
+ public Set<String> getSupportedTypes() {
+ return Collections.singleton(TestUtil.NT_TEST);
+ }
+ };
+
+ //add content
+ Tree test = root.getTree("/").addChild("test");
+ Tree node = createNodeWithType(test, "item", TestUtil.NT_TEST);
+ node.setProperty("foo", realSearchText);
+ root.commit();
+
+ //query (testSearchText doesn't have 'bar'... our augment would search for :fulltext:bar
+ String query = "select [jcr:path] from [oak:TestNode] where CONTAINS(*, '" + testSearchText + "')";
+ List<String> paths = executeQuery(query, SQL2);
+ assertEquals("Augmented query wasn't used to search", 1, paths.size());
+ assertEquals("/test/item", paths.get(0));
+ }
+
+ //OAK-3576
+ @Test public void indexHookCallbackFrequency() throws Exception {
+ //setup repo and index
+ NodeTypeRegistry.register(root, IOUtils.toInputStream(TestUtil.TEST_NODE_TYPE), "test nodeType");
+ Tree props = createIndex(TestUtil.NT_TEST);
+ TestUtil.enablePropertyIndex(props, "foo1", false);
+ TestUtil.enablePropertyIndex(props, "foo2", false);
+ TestUtil.enablePropertyIndex(props, "subChild/foo3", false);
+ root.commit();
+
+ //setup index augmentor
+ final AtomicInteger counter = new AtomicInteger(0);
+ factory.indexFieldProvider = new IndexFieldProvider() {
+ @Nonnull
+ @Override
+ public Iterable<Field> getAugmentedFields(String path, NodeState document, NodeState indexDefinition) {
+ counter.incrementAndGet();
+ return IndexFieldProvider.DEFAULT.getAugmentedFields(path, document, indexDefinition);
+ }
+
+ @Nonnull
+ @Override
+ public Set<String> getSupportedTypes() {
+ return Collections.singleton(TestUtil.NT_TEST);
+ }
+ };
+
+ //add content
+ counter.set(0);
+ Tree test = root.getTree("/").addChild("test");
+ Tree node = createNodeWithType(test, "item", TestUtil.NT_TEST);
+ node.setProperty("foo1", "bar1");
+ node.setProperty("foo2", "bar2");
+ Tree subChild = node.addChild("subChild");
+ subChild.setProperty("foo3", "bar3");
+ root.commit();
+ assertEquals("Number of callbacks should be same as number of changed properties", 1, counter.get());
+
+ //change sub-property
+ counter.set(0);
+ subChild = root.getTree("/test/item/subChild");
+ subChild.setProperty("foo3", "bar4");
+ root.commit();
+ assertEquals("Sub child property change should make call backs for all indexed properties", 1, counter.get());
+ }
+
+ //OAK-3576
+ @Test public void indexHookCallbackAndStorage() throws Exception {
+ final String propName = "subChild/foo";
+
+ //setup repo and index
+ NodeTypeRegistry.register(root, IOUtils.toInputStream(TestUtil.TEST_NODE_TYPE), "test nodeType");
+ Tree props = createIndex(TestUtil.NT_TEST);
+ TestUtil.enableForFullText(props, propName);
+ root.commit();
+
+ //setup index augmentor
+ factory.indexFieldProvider = new IndexFieldProvider() {
+ @Nonnull
+ @Override
+ public Iterable<Field> getAugmentedFields(String path, NodeState document, NodeState indexDefinition) {
+ assertEquals("/test/item", path);
+ assertEquals(TestUtil.NT_TEST, document.getName(JcrConstants.JCR_PRIMARYTYPE));
+ assertEquals(IndexConstants.INDEX_DEFINITIONS_NODE_TYPE,
+ indexDefinition.getName(JcrConstants.JCR_PRIMARYTYPE));
+ return Lists.<Field>newArrayList(new StringField("barbar", "1", Field.Store.NO));
+ }
+
+ @Nonnull
+ @Override
+ public Set<String> getSupportedTypes() {
+ return Collections.singleton(TestUtil.NT_TEST);
+ }
+ };
+
+ //add content
+ Tree test = root.getTree("/").addChild("test");
+ Tree node = createNodeWithType(test, "item", TestUtil.NT_TEST).addChild("subChild");
+ node.setProperty("foo", "bar");
+ root.commit();
+
+ //Check document that made to the index
+ IndexSearcher searcher = getSearcher();
+ TopDocs docs = searcher.search(new TermQuery(new Term("barbar", "1")), 10);
+ ScoreDoc[] scoreDocs = docs.scoreDocs;
+ assertEquals("Number of results should be 1", 1, scoreDocs.length);
+ Document doc = searcher.doc(scoreDocs[0].doc);
+ String path = doc.get(":path");
+ assertEquals("/test/item", path);
+ }
+
+ //OAK-3576
+ @Test
+ public void nullBehavior() throws Exception {
+ //setup repo and index
+ NodeTypeRegistry.register(root, IOUtils.toInputStream(TestUtil.TEST_NODE_TYPE), "test nodeType");
+ Tree props = createIndex(TestUtil.NT_TEST);
+ TestUtil.enableForFullText(props, "foo");
+ root.commit();
+
+ Tree rootTree = root.getTree("/").addChild("test");
+
+ //Note: augmentor behavior is tested elsewhere... we are just checking if default works
+
+ int testIndex = 1;
+ //both query and index augmentors are null (no exception expected)
+ checkSimpleBehavior(rootTree, testIndex++);
+
+ //Set a very sad query augmentor
+ factory.fulltextQueryTermsProvider = new FulltextQueryTermsProvider() {
+ @Override
+ public Query getQueryTerm(String text, Analyzer analyzer) {
+ return null;
+ }
+
+ @Nonnull
+ @Override
+ public Set<String> getSupportedTypes() {
+ return FulltextQueryTermsProvider.DEFAULT.getSupportedTypes();
+ }
+ };
+ checkSimpleBehavior(rootTree, testIndex++);
+
+ //Set query augmentor... with null query
+ factory.fulltextQueryTermsProvider = new FulltextQueryTermsProvider() {
+ @Override
+ public Query getQueryTerm(String text, Analyzer analyzer) {
+ return null;
+ }
+
+ @Nonnull
+ @Override
+ public Set<String> getSupportedTypes() {
+ return Collections.singleton(TestUtil.NT_TEST);
+ }
+ };
+ checkSimpleBehavior(rootTree, testIndex++);
+
+ //Set query augmentor... with some query
+ factory.fulltextQueryTermsProvider = new FulltextQueryTermsProvider() {
+ @Override
+ public Query getQueryTerm(String text, Analyzer analyzer) {
+ return new TermQuery(new Term("bar", "baz"));
+ }
+
+ @Nonnull
+ @Override
+ public Set<String> getSupportedTypes() {
+ return Collections.singleton(TestUtil.NT_TEST);
+ }
+ };
+ checkSimpleBehavior(rootTree, testIndex++);
+
+ factory.fulltextQueryTermsProvider = null;
+
+ //Set a very sad index augmentor
+ factory.indexFieldProvider = IndexFieldProvider.DEFAULT;
+ checkSimpleBehavior(rootTree, testIndex++);
+
+ //Set index augmentor... with null fields
+ factory.indexFieldProvider = new IndexFieldProvider() {
+ @Nonnull
+ @Override
+ public Iterable<Field> getAugmentedFields(String path, NodeState document, NodeState indexDefinition) {
+ return IndexFieldProvider.DEFAULT.getAugmentedFields(path, document, indexDefinition);
+ }
+
+ @Nonnull
+ @Override
+ public Set<String> getSupportedTypes() {
+ return Collections.singleton(TestUtil.NT_TEST);
+ }
+ };
+ checkSimpleBehavior(rootTree, testIndex++);
+
+ //Set index augmentor... with some fields
+ factory.fulltextQueryTermsProvider = null;
+ factory.indexFieldProvider = new IndexFieldProvider() {
+ @Nonnull
+ @Override
+ public Iterable<Field> getAugmentedFields(String path, NodeState document, NodeState indexDefinition) {
+ List<Field> fields = Lists.newArrayList();
+ fields.add(new StringField("bar", "baz", Field.Store.NO));
+ return fields;
+ }
+
+ @Nonnull
+ @Override
+ public Set<String> getSupportedTypes() {
+ return Collections.singleton(TestUtil.NT_TEST);
+ }
+ };
+ checkSimpleBehavior(rootTree, testIndex++);
+ }
+
+ //OAK-3576
+ @Test
+ public void skipDefaultOnlyUsingAugmentors() throws Exception {
+ //setup repo and index
+ NodeTypeRegistry.register(root, IOUtils.toInputStream(TestUtil.TEST_NODE_TYPE), "test nodeType");
+ Tree props = createIndex(TestUtil.NT_TEST);
+ Tree prop = props.addChild("foo1");
+ prop.setProperty(LuceneIndexConstants.PROP_INDEX, true);
+ prop = props.addChild("foo2");
+ prop.setProperty(LuceneIndexConstants.PROP_NAME, "subChild/foo2");
+ prop.setProperty(LuceneIndexConstants.PROP_INDEX, true);
+ root.commit();
+
+ //setup augmentors
+ final AtomicInteger indexingCounter = new AtomicInteger(0);
+ factory.indexFieldProvider = new IndexFieldProvider() {
+ @Nonnull
+ @Override
+ public Iterable<Field> getAugmentedFields(String path, NodeState document, NodeState indexDefinition) {
+ indexingCounter.incrementAndGet();
+ return IndexFieldProvider.DEFAULT.getAugmentedFields(path, document, indexDefinition);
+ }
+
+ @Nonnull
+ @Override
+ public Set<String> getSupportedTypes() {
+ return Collections.singleton(TestUtil.NT_TEST);
+ }
+ };
+ final AtomicInteger queryingCounter = new AtomicInteger(0);
+ factory.fulltextQueryTermsProvider = new FulltextQueryTermsProvider() {
+ @Override
+ public Query getQueryTerm(String text, Analyzer analyzer) {
+ queryingCounter.set(1);
+ return null;
+ }
+
+ @Nonnull
+ @Override
+ public Set<String> getSupportedTypes() {
+ return Collections.singleton(TestUtil.NT_TEST);
+ }
+ };
+
+ //add content
+ Tree node1 = createNodeWithType(root.getTree("/"), "node1", TestUtil.NT_TEST);
+ node1.setProperty("foo1", "bar1");
+ node1.addChild("subChild").setProperty("foo2", "bar2");
+ root.commit();
+
+ //indexing assertions
+ assertEquals("Indexing augment should get called once", 1, indexingCounter.get());
+ assertEquals("No docs should get indexed (augmentor hasn't added any field)",
+ 0, getSearcher().getIndexReader().numDocs());
+
+ String query = "EXPLAIN SELECT [jcr:path] from [" + TestUtil.NT_TEST + "] WHERE [foo1]='bar1'";
+ List<String> paths = executeQuery(query, SQL2);
+ assertTrue("indexed prop name shouldn't decide query plan (" + paths.get(0) + ")",
+ paths.get(0).contains("/* no-index "));
+
+ query = "EXPLAIN SELECT [jcr:path] from [" + TestUtil.NT_TEST + "] WHERE [subChild/foo2]='bar2'";
+ paths = executeQuery(query, SQL2);
+ assertTrue("indexed prop name shouldn't decide query plan (" + paths.get(0) + ")",
+ paths.get(0).contains("/* no-index "));
+ }
+
+ //OAK-3576
+ @Test
+ public void propertyIndexUsingAugmentors() throws Exception {
+ //setup repo and index
+ NodeTypeRegistry.register(root, IOUtils.toInputStream(TestUtil.TEST_NODE_TYPE), "test nodeType");
+ Tree props = createIndex(TestUtil.NT_TEST);
+ TestUtil.enablePropertyIndex(props, "foo1", false);
+ TestUtil.enablePropertyIndex(props, "subChild/foo2", false);
+ root.commit();
+
+ //setup augmentors
+ final AtomicInteger indexingCounter = new AtomicInteger(0);
+ factory.indexFieldProvider = new IndexFieldProvider() {
+ @Nonnull
+ @Override
+ public Iterable<Field> getAugmentedFields(String path, NodeState document, NodeState indexDefinition) {
+ indexingCounter.incrementAndGet();
+ return IndexFieldProvider.DEFAULT.getAugmentedFields(path, document, indexDefinition);
+ }
+
+ @Nonnull
+ @Override
+ public Set<String> getSupportedTypes() {
+ return Collections.singleton(TestUtil.NT_TEST);
+ }
+ };
+ final AtomicInteger queryingCounter = new AtomicInteger(0);
+ factory.fulltextQueryTermsProvider = new FulltextQueryTermsProvider() {
+ @Override
+ public Query getQueryTerm(String text, Analyzer analyzer) {
+ queryingCounter.set(1);
+ return null;
+ }
+
+ @Nonnull
+ @Override
+ public Set<String> getSupportedTypes() {
+ return Collections.singleton(TestUtil.NT_TEST);
+ }
+ };
+
+ //add content
+ Tree node1 = createNodeWithType(root.getTree("/"), "node1", TestUtil.NT_TEST);
+ node1.setProperty("foo1", "bar1");
+ node1.addChild("subChild").setProperty("foo2", "bar2");
+ root.commit();
+
+ //indexing assertions
+ assertEquals("Indexing augment should get called once", 1, indexingCounter.get());
+
+ String query = "SELECT [jcr:path] from [" + TestUtil.NT_TEST + "] WHERE [foo1]='bar1'";
+ executeQuery(query, SQL2);
+ assertEquals("Query augmentor should not get called for property constraints", 0, queryingCounter.get());
+ query = "EXPLAIN " + query;
+ List<String> paths = executeQuery(query, SQL2, false);
+ assertTrue("property index should have made the index selected (" + paths.get(0) + ")",
+ paths.get(0).contains("/* lucene:test-index("));
+
+ query = "SELECT [jcr:path] from [" + TestUtil.NT_TEST + "] WHERE [subChild/foo2]='bar2'";
+ executeQuery(query, SQL2);
+ assertEquals("Query augmentor should not get called for property constraints", 0, queryingCounter.get());
+ query = "EXPLAIN " + query;
+ paths = executeQuery(query, SQL2);
+ assertTrue("property index should have made the index selected (" + paths.get(0) + ")",
+ paths.get(0).contains("/* lucene:test-index("));
+ }
+
+ //OAK-3576
+ @Test
+ public void fulltextIndexUsingAugmentors() throws Exception {
+ //setup repo and index
+ NodeTypeRegistry.register(root, IOUtils.toInputStream(TestUtil.TEST_NODE_TYPE), "test nodeType");
+ Tree props = createIndex(TestUtil.NT_TEST);
+ TestUtil.enableForFullText(props, "foo1");
+ TestUtil.enableForFullText(props, "subChild/foo2");
+ root.commit();
+
+ //setup augmentors
+ final AtomicInteger indexingCounter = new AtomicInteger(0);
+ factory.indexFieldProvider = new IndexFieldProvider() {
+ @Nonnull
+ @Override
+ public Iterable<Field> getAugmentedFields(String path, NodeState document, NodeState indexDefinition) {
+ indexingCounter.incrementAndGet();
+ return IndexFieldProvider.DEFAULT.getAugmentedFields(path, document, indexDefinition);
+ }
+
+ @Nonnull
+ @Override
+ public Set<String> getSupportedTypes() {
+ return Collections.singleton(TestUtil.NT_TEST);
+ }
+ };
+ final AtomicInteger queryingCounter = new AtomicInteger(0);
+ factory.fulltextQueryTermsProvider = new FulltextQueryTermsProvider() {
+ @Override
+ public Query getQueryTerm(String text, Analyzer analyzer) {
+ queryingCounter.set(1);
+ return null;
+ }
+
+ @Nonnull
+ @Override
+ public Set<String> getSupportedTypes() {
+ return Collections.singleton(TestUtil.NT_TEST);
+ }
+ };
+
+ //add content
+ Tree node1 = createNodeWithType(root.getTree("/"), "node1", TestUtil.NT_TEST);
+ node1.setProperty("foo1", "bar1");
+ node1.addChild("subChild").setProperty("foo2", "bar2");
+ root.commit();
+
+ //indexing assertions
+ assertEquals("Indexing augment should get called once", 1, indexingCounter.get());
+
+ String query = "SELECT [jcr:path] from [" + TestUtil.NT_TEST + "] WHERE CONTAINS(*, 'bar1')";
+ executeQuery(query, SQL2);
+ assertEquals("Query augmentor should get called for full text constraints", 1, queryingCounter.get());
+ queryingCounter.set(0);
+ query = "EXPLAIN " + query;
+ List<String> paths = executeQuery(query, SQL2, false);
+ assertEquals("Query augmentor should get called for full text constraints", 1, queryingCounter.get());
+ assertTrue("property index should have made the index selected (" + paths.get(0) + ")",
+ paths.get(0).contains("/* lucene:test-index("));
+
+ queryingCounter.set(0);
+ query = "SELECT [jcr:path] from [" + TestUtil.NT_TEST + "] WHERE CONTAINS(*, 'bar2')";
+ executeQuery(query, SQL2);
+ assertEquals("Query augmentor should get called for full text constraints", 1, queryingCounter.get());
+ queryingCounter.set(0);
+ query = "EXPLAIN " + query;
+ paths = executeQuery(query, SQL2, false);
+ assertEquals("Query augmentor should get called for full text constraints", 1, queryingCounter.get());
+ assertTrue("property index should have made the index selected (" + paths.get(0) + ")",
+ paths.get(0).contains("/* lucene:test-index("));
+ }
+
+ @Test
+ public void indexAugmentorMismatchedNodeType() throws Exception {
+ //setup repo and index
+ NodeTypeRegistry.register(root, IOUtils.toInputStream(TestUtil.TEST_NODE_TYPE), "test nodeType");
+ Tree props = createIndex(TestUtil.NT_TEST);
+ TestUtil.enableForFullText(props, "foo1");
+ root.commit();
+
+ //setup augmentors
+ final AtomicInteger indexingCounter1 = new AtomicInteger(0);
+ final AtomicInteger indexingCounter2 = new AtomicInteger(0);
+ factory.registerIndexFieldProvider(new IndexFieldProvider() {
+ @Nonnull
+ @Override
+ public Iterable<Field> getAugmentedFields(String path, NodeState document, NodeState indexDefinition) {
+ indexingCounter1.incrementAndGet();
+ return IndexFieldProvider.DEFAULT.getAugmentedFields(path, document, indexDefinition);
+ }
+
+ @Nonnull
+ @Override
+ public Set<String> getSupportedTypes() {
+ return Collections.singleton(JcrConstants.NT_BASE);
+ }
+ });
+ factory.registerIndexFieldProvider(new IndexFieldProvider() {
+ @Nonnull
+ @Override
+ public Iterable<Field> getAugmentedFields(String path, NodeState document, NodeState indexDefinition) {
+ indexingCounter2.incrementAndGet();
+ return IndexFieldProvider.DEFAULT.getAugmentedFields(path, document, indexDefinition);
+ }
+
+ @Nonnull
+ @Override
+ public Set<String> getSupportedTypes() {
+ return Collections.singleton(TestUtil.NT_TEST);
+ }
+ });
+ factory.useSuperBehavior = true;
+
+ //add content
+ createNodeWithType(root.getTree("/"), "node1", TestUtil.NT_TEST).setProperty("foo1", "bar1");
+ root.commit();
+
+ assertEquals("Mismatching node type should not let index augmentor called", 0, indexingCounter1.get());
+ assertEquals("Matching node type should get augmentor called", 1, indexingCounter2.get());
+ }
+
+ @Test
+ public void queryAugmentorMismatchedNodeType() throws Exception {
+ //setup repo and index
+ NodeTypeRegistry.register(root, IOUtils.toInputStream(TestUtil.TEST_NODE_TYPE), "test nodeType");
+ Tree props = createIndex(TestUtil.NT_TEST);
+ TestUtil.enableForFullText(props, "foo1", false);
+ root.commit();
+
+ //setup augmentors
+ final AtomicInteger indexingCounter1 = new AtomicInteger(0);
+ final AtomicInteger indexingCounter2 = new AtomicInteger(0);
+ factory.registerQueryTermsProvider(new FulltextQueryTermsProvider() {
+ @Override
+ public Query getQueryTerm(String text, Analyzer analyzer) {
+ indexingCounter1.set(1);
+ return null;
+ }
+
+ @Nonnull
+ @Override
+ public Set<String> getSupportedTypes() {
+ return Collections.singleton(JcrConstants.NT_BASE);
+ }
+ });
+ factory.registerQueryTermsProvider(new FulltextQueryTermsProvider() {
+ @Override
+ public Query getQueryTerm(String text, Analyzer analyzer) {
+ indexingCounter2.set(1);
+ return null;
+ }
+
+ @Nonnull
+ @Override
+ public Set<String> getSupportedTypes() {
+ return Collections.singleton(TestUtil.NT_TEST);
+ }
+ });
+ factory.useSuperBehavior = true;
+
+
+ executeQuery("SELECT [jcr:path] FROM [" + TestUtil.NT_TEST + "] WHERE CONTAINS(*, 'test')", SQL2, false);
+
+ assertEquals("Mismatching node type should not let index augmentor called", 0, indexingCounter1.get());
+ assertEquals("Matching node type should get augmentor called", 1, indexingCounter2.get());
+ }
+
+ private static Tree createNodeWithType(Tree t, String nodeName, String typeName){
+ t = t.addChild(nodeName);
+ t.setProperty(JcrConstants.JCR_PRIMARYTYPE, typeName, Type.NAME);
+ return t;
+ }
+
+ private Tree createIndex(String nodeType) throws Exception {
+ Tree rootTree = root.getTree("/");
+ return createIndex(rootTree, nodeType);
+ }
+
+ private Tree createIndex(Tree root, String nodeType) throws Exception {
+ Tree index = createTestIndexNode(root, LuceneIndexConstants.TYPE_LUCENE);
+ return TestUtil.newRulePropTree(index, nodeType);
+ }
+
+ private static class SimpleIndexAugmentorFactory extends IndexAugmentorFactory {
+ IndexFieldProvider indexFieldProvider = null;
+ FulltextQueryTermsProvider fulltextQueryTermsProvider = null;
+ private boolean useSuperBehavior = false;
+ private final Whiteboard whiteboard;
+
+ SimpleIndexAugmentorFactory() {
+ this(new DefaultWhiteboard());
+ }
+
+ SimpleIndexAugmentorFactory(Whiteboard whiteboard) {
+ super(whiteboard);
+ this.whiteboard = whiteboard;
+ }
+
+ void registerIndexFieldProvider(IndexFieldProvider provider) {
+ whiteboard.register(IndexFieldProvider.class, provider, null);
+ refreshServices();
+ }
+
+ void registerQueryTermsProvider(FulltextQueryTermsProvider provider) {
+ whiteboard.register(FulltextQueryTermsProvider.class, provider, null);
+ refreshServices();
+ }
+
+ @Nonnull
+ @Override
+ public IndexFieldProvider getIndexFieldProvider(String nodeType) {
+ return useSuperBehavior?
+ super.getIndexFieldProvider(nodeType):
+ (indexFieldProvider != null)?
+ indexFieldProvider:
+ IndexFieldProvider.DEFAULT;
+ }
+
+ @Nonnull
+ @Override
+ public FulltextQueryTermsProvider getFulltextQueryTermsProvider(String nodeType) {
+ return useSuperBehavior?
+ super.getFulltextQueryTermsProvider(nodeType):
+ (fulltextQueryTermsProvider != null)?
+ fulltextQueryTermsProvider:
+ FulltextQueryTermsProvider.DEFAULT;
+ }
+ }
+
+ private IndexSearcher getSearcher(){
+ if(indexNode == null){
+ indexNode = tracker.acquireIndexNode("/oak:index/" + TEST_INDEX_NAME);
+ }
+ return indexNode.getSearcher();
+ }
+
+ private void checkSimpleBehavior(Tree rootTree, int testIndex) throws Exception {
+ createNodeWithType(rootTree, "node" + testIndex, TestUtil.NT_TEST)
+ .setProperty("foo", "bar" + testIndex);
+ root.commit();
+
+ String query = "SELECT [jcr:path] from [" + TestUtil.NT_TEST + "] WHERE contains(*, 'bar" + testIndex + "')";
+ List<String> paths = executeQuery(query, SQL2);
+ assertEquals(1, paths.size());
+ assertEquals("/test/node" + testIndex, paths.get(0));
+ }
+}
Propchange: jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexAugmentTest.java
------------------------------------------------------------------------------
svn:eol-style = native