Index: src/main/java/org/apache/jackrabbit/core/query/lucene/QueryImpl.java =================================================================== --- src/main/java/org/apache/jackrabbit/core/query/lucene/QueryImpl.java (revision 568963) +++ src/main/java/org/apache/jackrabbit/core/query/lucene/QueryImpl.java (working copy) @@ -146,7 +146,7 @@ // build lucene query Query query = LuceneQueryBuilder.createQuery(root, session, index.getContext().getItemStateManager(), index.getNamespaceMappings(), - index.getTextAnalyzer(), propReg, index.getSynonymProvider()); + index.getTextAnalyzer(), propReg, index.getSynonymProvider(), index.getNewIndexFormat()); OrderQueryNode orderNode = root.getOrderNode(); Index: src/main/java/org/apache/jackrabbit/core/query/lucene/NodeIndexer.java =================================================================== --- src/main/java/org/apache/jackrabbit/core/query/lucene/NodeIndexer.java (revision 568963) +++ src/main/java/org/apache/jackrabbit/core/query/lucene/NodeIndexer.java (working copy) @@ -96,6 +96,11 @@ protected boolean supportHighlighting = false; /** + * Indicates if the index format is new or old. + */ + protected boolean newIndexFormat = true; + + /** * Creates a new node indexer. * * @param node the node state to index. @@ -132,6 +137,15 @@ } /** + * Sets wether the index is of new format. + * + * @param format when true, format is new. + */ + public void setNewIndexFormat(boolean format) { + this.newIndexFormat = format; + } + + /** * Sets the indexing configuration for this node indexer. * * @param config the indexing configuration. @@ -189,6 +203,13 @@ PropertyId id = new PropertyId(node.getNodeId(), propName); try { PropertyState propState = (PropertyState) stateProvider.getItemState(id); + + // add each property to the _PROPERTIES_SET for searching + // if index format is new + if(newIndexFormat) { + addPropertyName(doc,propState.getName()); + } + InternalValue[] values = propState.getValues(); for (int i = 0; i < values.length; i++) { addValue(doc, values[i], propState.getName()); @@ -313,6 +334,22 @@ } /** + * Adds the propertyname to the lucene _PROPERTIES_SET field. + * + * @param doc the document. + * @param name the name of the property. + */ + private void addPropertyName(Document doc, QName name) { + String fieldName = name.getLocalName(); + try { + fieldName = NameFormat.format(name, mappings); + } catch (NoPrefixDeclaredException e) { + // will never happen + } + doc.add(new Field(FieldNames.PROPERTIES_SET,fieldName,Field.Store.NO,Field.Index.NO_NORMS)); + } + + /** * Adds the binary value to the document as the named field. *
* This implementation checks if this {@link #node} is of type nt:resource Index: src/main/java/org/apache/jackrabbit/core/query/lucene/FieldNames.java =================================================================== --- src/main/java/org/apache/jackrabbit/core/query/lucene/FieldNames.java (revision 568963) +++ src/main/java/org/apache/jackrabbit/core/query/lucene/FieldNames.java (working copy) @@ -71,6 +71,12 @@ public static final String PROPERTIES = "_:PROPERTIES".intern(); /** + * Name of the field that contains all available properties that are available + * for this indexed node. + */ + public static final String PROPERTIES_SET = "_:PROPERTIES_SET".intern(); + + /** * Name of the field that contains the UUIDs of the aggregated nodes. The * terms are not tokenized and not stored, only indexed. */ Index: src/main/java/org/apache/jackrabbit/core/query/lucene/SearchIndex.java =================================================================== --- src/main/java/org/apache/jackrabbit/core/query/lucene/SearchIndex.java (revision 568963) +++ src/main/java/org/apache/jackrabbit/core/query/lucene/SearchIndex.java (working copy) @@ -16,58 +16,60 @@ */ package org.apache.jackrabbit.core.query.lucene; +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.jcr.RepositoryException; +import javax.jcr.query.InvalidQueryException; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + +import org.apache.commons.collections.iterators.AbstractIteratorDecorator; import org.apache.jackrabbit.core.ItemManager; -import org.apache.jackrabbit.core.SessionImpl; import org.apache.jackrabbit.core.NodeId; import org.apache.jackrabbit.core.NodeIdIterator; +import org.apache.jackrabbit.core.SessionImpl; import org.apache.jackrabbit.core.query.AbstractQueryHandler; import org.apache.jackrabbit.core.query.ExecutableQuery; +import org.apache.jackrabbit.core.query.QueryHandler; import org.apache.jackrabbit.core.query.QueryHandlerContext; -import org.apache.jackrabbit.core.query.QueryHandler; +import org.apache.jackrabbit.core.state.ItemStateManager; import org.apache.jackrabbit.core.state.NodeState; import org.apache.jackrabbit.core.state.NodeStateIterator; -import org.apache.jackrabbit.core.state.ItemStateManager; import org.apache.jackrabbit.extractor.DefaultTextExtractor; import org.apache.jackrabbit.extractor.TextExtractor; +import org.apache.jackrabbit.name.NameFormat; import org.apache.jackrabbit.name.NoPrefixDeclaredException; import org.apache.jackrabbit.name.QName; -import org.apache.jackrabbit.name.NameFormat; import org.apache.jackrabbit.uuid.UUID; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.analysis.standard.StandardAnalyzer; +import org.apache.lucene.document.Document; +import org.apache.lucene.document.Field; import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.MultiReader; import org.apache.lucene.index.Term; import org.apache.lucene.index.TermDocs; +import org.apache.lucene.index.IndexReader.FieldOption; import org.apache.lucene.search.Hits; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; import org.apache.lucene.search.Sort; import org.apache.lucene.search.SortField; -import org.apache.lucene.document.Document; -import org.apache.lucene.document.Field; -import org.apache.commons.collections.iterators.AbstractIteratorDecorator; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.w3c.dom.Element; import org.xml.sax.SAXException; -import org.w3c.dom.Element; -import javax.jcr.RepositoryException; -import javax.jcr.query.InvalidQueryException; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.ParserConfigurationException; -import java.io.IOException; -import java.io.File; -import java.util.Iterator; -import java.util.List; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.Set; -import java.util.Arrays; -import java.util.HashMap; -import java.util.Map; - /** * Implements a {@link org.apache.jackrabbit.core.query.QueryHandler} using * Lucene. @@ -302,6 +304,13 @@ private boolean closed = false; /** + * Indicates if thisSearchIndex index format is new.
+ * If you have multiple workspaces, some indices might
+ * be in the old format, while others in the new.
+ */
+ private boolean newIndexFormat = true;
+
+ /**
* Default constructor.
*/
public SearchIndex() {
@@ -375,6 +384,14 @@
log.warn("Failed to run consistency check on index: " + e);
}
}
+
+ newIndexFormat = index.getIndexReader().getFieldNames(
+ FieldOption.ALL).contains(FieldNames.PROPERTIES_SET)
+ || index.getIndexReader().numDocs() == 0;
+
+ if(!newIndexFormat)log.warn("Index is in old format. This might imply slower queries. " +
+ "Re-index if possible");
+
log.info("Index initialized: " + path);
}
@@ -703,6 +720,7 @@
getContext().getItemStateManager(), nsMappings, extractor);
indexer.setSupportHighlighting(supportHighlighting);
indexer.setIndexingConfiguration(indexingConfig);
+ indexer.setNewIndexFormat(newIndexFormat);
Document doc = indexer.createDoc();
mergeAggregatedNodeIndexes(node, doc);
return doc;
@@ -1470,7 +1488,15 @@
public boolean getEnableConsistencyCheck() {
return consistencyCheckEnabled;
}
-
+
+ /**
+ * @return true if the index format is in the new format;
+ * false otherwise.
+ */
+ public boolean getNewIndexFormat() {
+ return newIndexFormat;
+ }
+
//----------------------------< internal >----------------------------------
/**
Index: src/main/java/org/apache/jackrabbit/core/query/lucene/LuceneQueryBuilder.java
===================================================================
--- src/main/java/org/apache/jackrabbit/core/query/lucene/LuceneQueryBuilder.java (revision 568963)
+++ src/main/java/org/apache/jackrabbit/core/query/lucene/LuceneQueryBuilder.java (working copy)
@@ -130,6 +130,11 @@
private SynonymProvider synonymProvider;
/**
+ * The wether the index format is new or old.
+ */
+ private boolean newIndexFormat;
+
+ /**
* Exceptions thrown during tree translation
*/
private List exceptions = new ArrayList();
@@ -155,7 +160,8 @@
NamespaceMappings nsMappings,
Analyzer analyzer,
PropertyTypeRegistry propReg,
- SynonymProvider synonymProvider) {
+ SynonymProvider synonymProvider,
+ boolean newIndexFormat) {
this.root = root;
this.session = session;
this.sharedItemMgr = sharedItemMgr;
@@ -164,6 +170,7 @@
this.analyzer = analyzer;
this.propRegistry = propReg;
this.synonymProvider = synonymProvider;
+ this.newIndexFormat = newIndexFormat;
}
/**
@@ -189,7 +196,7 @@
PropertyTypeRegistry propReg)
throws RepositoryException {
return createQuery(root, session, sharedItemMgr,
- nsMappings, analyzer, propReg, null);
+ nsMappings, analyzer, propReg, null, true);
}
/**
@@ -215,7 +222,8 @@
NamespaceMappings nsMappings,
Analyzer analyzer,
PropertyTypeRegistry propReg,
- SynonymProvider synonymProvider)
+ SynonymProvider synonymProvider,
+ boolean newIndexFormat)
throws RepositoryException {
NodeId id = ((NodeImpl) session.getRootNode()).getNodeId();
@@ -223,7 +231,7 @@
id, sharedItemMgr, session);
LuceneQueryBuilder builder = new LuceneQueryBuilder(
root, session, sharedItemMgr, hmgr, nsMappings,
- analyzer, propReg, synonymProvider);
+ analyzer, propReg, synonymProvider, newIndexFormat);
Query q = builder.createLuceneQuery();
if (builder.exceptions.size() > 0) {
@@ -569,7 +577,7 @@
// todo this will traverse the whole index, optimize!
Query subQuery = null;
try {
- subQuery = new MatchAllQuery(NameFormat.format(QName.JCR_PRIMARYTYPE, nsMappings));
+ subQuery = getMatchAllQuery(NameFormat.format(QName.JCR_PRIMARYTYPE, nsMappings));
} catch (NoPrefixDeclaredException e) {
// will never happen, prefixes are created when unknown
}
@@ -610,7 +618,7 @@
}
if (node.getIncludeDescendants()) {
- Query refPropQuery = new MatchAllQuery(refProperty);
+ Query refPropQuery = getMatchAllQuery(refProperty);
context = new DescendantSelfAxisQuery(context, refPropQuery, false);
}
@@ -815,7 +823,7 @@
// the like operation always has one string value.
// no coercing, see above
if (stringValues[0].equals("%")) {
- query = new MatchAllQuery(field);
+ query = getMatchAllQuery(field);
} else {
query = new WildcardQuery(FieldNames.PROPERTIES, field, stringValues[0], transform[0]);
}
@@ -836,7 +844,7 @@
case QueryConstants.OPERATION_NE_VALUE: // !=
// match nodes with property 'field' that includes svp and mvp
BooleanQuery notQuery = new BooleanQuery();
- notQuery.add(new MatchAllQuery(field), Occur.SHOULD);
+ notQuery.add(getMatchAllQuery(field), Occur.SHOULD);
// exclude all nodes where 'field' has the term in question
for (int i = 0; i < stringValues.length; i++) {
Term t = new Term(FieldNames.PROPERTIES, FieldNames.createNamedValue(field, stringValues[i]));
@@ -862,7 +870,7 @@
// minus the nodes that have a multi-valued property 'field' and
// all values are equal to term in question
notQuery = new BooleanQuery();
- notQuery.add(new MatchAllQuery(field), Occur.SHOULD);
+ notQuery.add(getMatchAllQuery(field), Occur.SHOULD);
for (int i = 0; i < stringValues.length; i++) {
// exclude the nodes that have the term and are single valued
Term t = new Term(FieldNames.PROPERTIES, FieldNames.createNamedValue(field, stringValues[i]));
@@ -885,7 +893,7 @@
query = notQuery;
break;
case QueryConstants.OPERATION_NULL:
- query = new NotQuery(new MatchAllQuery(field));
+ query = new NotQuery(getMatchAllQuery(field));
break;
case QueryConstants.OPERATION_SIMILAR:
String uuid = "x";
@@ -900,7 +908,7 @@
query = new SimilarityQuery(uuid, analyzer);
break;
case QueryConstants.OPERATION_NOT_NULL:
- query = new MatchAllQuery(field);
+ query = getMatchAllQuery(field);
break;
default:
throw new IllegalArgumentException("Unknown relation operation: "
@@ -1108,4 +1116,19 @@
}
return (String[]) values.toArray(new String[values.size()]);
}
+
+ /**
+ * Depeding wether the index is of the new index format this method
+ * returns a query that matches all nodes that have property 'field'
+ *
+ * @param field
+ * @return Query that matches all nodes that contain the property field
+ */
+ private final Query getMatchAllQuery(String field){
+ if(this.newIndexFormat) {
+ return new TermQuery(new Term(FieldNames.PROPERTIES_SET,field));
+ } else {
+ return new MatchAllQuery(field);
+ }
+ }
}