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