You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by ju...@apache.org on 2010/10/19 17:06:41 UTC
svn commit: r1024259 - in
/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene:
LuceneQueryFactory.java LuceneQueryFactoryImpl.java QueryObjectModelImpl.java
Author: jukka
Date: Tue Oct 19 15:06:41 2010
New Revision: 1024259
URL: http://svn.apache.org/viewvc?rev=1024259&view=rev
Log:
JCR-2715: Improved join query performance
Inline LuceneQueryFactoryImpl into LuceneQueryFactory to simplify things since it's the only implementation of the interface.
Removed:
jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/LuceneQueryFactoryImpl.java
Modified:
jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/LuceneQueryFactory.java
jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/QueryObjectModelImpl.java
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/LuceneQueryFactory.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/LuceneQueryFactory.java?rev=1024259&r1=1024258&r2=1024259&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/LuceneQueryFactory.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/LuceneQueryFactory.java Tue Oct 19 15:06:41 2010
@@ -16,9 +16,35 @@
*/
package org.apache.jackrabbit.core.query.lucene;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
import javax.jcr.RepositoryException;
+import javax.jcr.Value;
+import javax.jcr.nodetype.NodeType;
+import javax.jcr.nodetype.NodeTypeIterator;
+import javax.jcr.nodetype.NodeTypeManager;
+import javax.jcr.query.InvalidQueryException;
+import javax.jcr.query.qom.Literal;
+import javax.jcr.query.qom.StaticOperand;
+import org.apache.lucene.analysis.Analyzer;
+import org.apache.lucene.index.Term;
+import org.apache.lucene.queryParser.ParseException;
+import org.apache.lucene.queryParser.QueryParser;
+import org.apache.lucene.search.BooleanClause;
+import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.Query;
+import org.apache.jackrabbit.core.HierarchyManager;
+import org.apache.jackrabbit.core.SessionImpl;
+import org.apache.jackrabbit.spi.Name;
+import org.apache.jackrabbit.spi.commons.conversion.NamePathResolver;
+import org.apache.jackrabbit.spi.commons.name.NameConstants;
+import org.apache.jackrabbit.spi.commons.query.qom.BindVariableValueImpl;
+import org.apache.jackrabbit.spi.commons.query.qom.DefaultQOMTreeVisitor;
+import org.apache.jackrabbit.spi.commons.query.qom.JoinConditionImpl;
import org.apache.jackrabbit.spi.commons.query.qom.SelectorImpl;
import org.apache.jackrabbit.spi.commons.query.qom.FullTextSearchImpl;
import org.apache.jackrabbit.spi.commons.query.qom.PropertyExistenceImpl;
@@ -26,10 +52,76 @@ import org.apache.jackrabbit.spi.commons
import org.apache.jackrabbit.spi.commons.query.qom.JoinImpl;
/**
- * <code>LuceneQueryFactory</code> implements a factory that creates lucene
- * queries from given QOM elements.
+ * Factory that creates Lucene queries from QOM elements.
*/
-public interface LuceneQueryFactory {
+public class LuceneQueryFactory {
+
+ /**
+ * Session of the user executing this query
+ */
+ private final SessionImpl session;
+
+ /**
+ * The hierarchy manager.
+ */
+ private final HierarchyManager hmgr;
+
+ /**
+ * Namespace mappings to internal prefixes
+ */
+ private final NamespaceMappings nsMappings;
+
+ /**
+ * NamePathResolver to map namespace mappings to internal prefixes
+ */
+ private final NamePathResolver npResolver;
+
+ /**
+ * The analyzer instance to use for contains function query parsing
+ */
+ private final Analyzer analyzer;
+
+ /**
+ * The synonym provider or <code>null</code> if none is configured.
+ */
+ private final SynonymProvider synonymProvider;
+
+ /**
+ * The index format version.
+ */
+ private final IndexFormatVersion version;
+
+ /**
+ * The Bind Variable values.
+ */
+ private final Map<Name, Value> bindVariables;
+
+ /**
+ * Creates a new lucene query factory.
+ *
+ * @param session the session that executes the query.
+ * @param scs the sort comparator source of the index.
+ * @param hmgr the hierarchy manager of the workspace.
+ * @param nsMappings the index internal namespace mappings.
+ * @param analyzer the analyzer of the index.
+ * @param synonymProvider the synonym provider of the index.
+ * @param version the version of the index format.
+ * @param bindVariables the bind variable values of the query
+ */
+ public LuceneQueryFactory(
+ SessionImpl session, HierarchyManager hmgr,
+ NamespaceMappings nsMappings, Analyzer analyzer,
+ SynonymProvider synonymProvider, IndexFormatVersion version,
+ Map<Name, Value> bindVariables) {
+ this.session = session;
+ this.hmgr = hmgr;
+ this.nsMappings = nsMappings;
+ this.analyzer = analyzer;
+ this.synonymProvider = synonymProvider;
+ this.version = version;
+ this.npResolver = NamePathResolverImpl.create(nsMappings);
+ this.bindVariables = bindVariables;
+ }
/**
* Creates a lucene query for the given QOM selector.
@@ -38,7 +130,68 @@ public interface LuceneQueryFactory {
* @return a lucene query for the given selector.
* @throws RepositoryException if an error occurs while creating the query.
*/
- public Query create(SelectorImpl selector) throws RepositoryException;
+ public Query create(SelectorImpl selector) throws RepositoryException {
+ List<Term> terms = new ArrayList<Term>();
+ String mixinTypesField = npResolver.getJCRName(NameConstants.JCR_MIXINTYPES);
+ String primaryTypeField = npResolver.getJCRName(NameConstants.JCR_PRIMARYTYPE);
+
+ NodeTypeManager ntMgr = session.getWorkspace().getNodeTypeManager();
+ NodeType base = null;
+ try {
+ base = ntMgr.getNodeType(session.getJCRName(selector.getNodeTypeQName()));
+ } catch (RepositoryException e) {
+ // node type does not exist
+ }
+
+ if (base != null && base.isMixin()) {
+ // search for nodes where jcr:mixinTypes is set to this mixin
+ Term t = new Term(FieldNames.PROPERTIES,
+ FieldNames.createNamedValue(mixinTypesField,
+ npResolver.getJCRName(selector.getNodeTypeQName())));
+ terms.add(t);
+ } else {
+ // search for nodes where jcr:primaryType is set to this type
+ Term t = new Term(FieldNames.PROPERTIES,
+ FieldNames.createNamedValue(primaryTypeField,
+ npResolver.getJCRName(selector.getNodeTypeQName())));
+ terms.add(t);
+ }
+
+ // now search for all node types that are derived from base
+ if (base != null) {
+ NodeTypeIterator allTypes = ntMgr.getAllNodeTypes();
+ while (allTypes.hasNext()) {
+ NodeType nt = allTypes.nextNodeType();
+ NodeType[] superTypes = nt.getSupertypes();
+ if (Arrays.asList(superTypes).contains(base)) {
+ Name n = session.getQName(nt.getName());
+ String ntName = nsMappings.translateName(n);
+ Term t;
+ if (nt.isMixin()) {
+ // search on jcr:mixinTypes
+ t = new Term(FieldNames.PROPERTIES,
+ FieldNames.createNamedValue(mixinTypesField, ntName));
+ } else {
+ // search on jcr:primaryType
+ t = new Term(FieldNames.PROPERTIES,
+ FieldNames.createNamedValue(primaryTypeField, ntName));
+ }
+ terms.add(t);
+ }
+ }
+ }
+ Query q;
+ if (terms.size() == 1) {
+ q = new JackrabbitTermQuery(terms.get(0));
+ } else {
+ BooleanQuery b = new BooleanQuery();
+ for (Term term : terms) {
+ b.add(new JackrabbitTermQuery(term), BooleanClause.Occur.SHOULD);
+ }
+ q = b;
+ }
+ return q;
+ }
/**
* Creates a lucene query for the given QOM full text search.
@@ -47,7 +200,42 @@ public interface LuceneQueryFactory {
* @return the lucene query for the given constraint.
* @throws RepositoryException if an error occurs while creating the query.
*/
- public Query create(FullTextSearchImpl constraint) throws RepositoryException;
+ public Query create(FullTextSearchImpl fts) throws RepositoryException {
+ String fieldname;
+ if (fts.getPropertyName() == null) {
+ // fulltext on node
+ fieldname = FieldNames.FULLTEXT;
+ } else {
+ // final path element is a property name
+ Name propName = fts.getPropertyQName();
+ StringBuffer tmp = new StringBuffer();
+ tmp.append(nsMappings.getPrefix(propName.getNamespaceURI()));
+ tmp.append(":").append(FieldNames.FULLTEXT_PREFIX);
+ tmp.append(propName.getLocalName());
+ fieldname = tmp.toString();
+ }
+ QueryParser parser = new JackrabbitQueryParser(
+ fieldname, analyzer, synonymProvider);
+ try {
+ StaticOperand expr = fts.getFullTextSearchExpression();
+ if (expr instanceof Literal) {
+ return parser.parse(
+ ((Literal) expr).getLiteralValue().getString());
+ } else if (expr instanceof BindVariableValueImpl) {
+ Value value = this.bindVariables.get(
+ ((BindVariableValueImpl) expr).getBindVariableQName());
+ if (value == null) {
+ throw new InvalidQueryException("Bind variable not bound");
+ }
+ return parser.parse(value.getString());
+ } else {
+ throw new RepositoryException(
+ "Unknown static operand type: " + expr);
+ }
+ } catch (ParseException e) {
+ throw new RepositoryException(e);
+ }
+ }
/**
* Creates a lucene query for the given QOM property existence constraint.
@@ -56,7 +244,10 @@ public interface LuceneQueryFactory {
* @return the lucene query for the given constraint.
* @throws RepositoryException if an error occurs while creating the query.
*/
- public Query create(PropertyExistenceImpl constraint) throws RepositoryException;
+ public Query create(PropertyExistenceImpl prop) throws RepositoryException {
+ String propName = npResolver.getJCRName(prop.getPropertyQName());
+ return Util.createMatchAllQuery(propName, version);
+ }
/**
* Creates a multi column query for the given QOM source.
@@ -65,7 +256,25 @@ public interface LuceneQueryFactory {
* @return a multi column query for the given source.
* @throws RepositoryException if an error occurs while creating the query.
*/
- public MultiColumnQuery create(SourceImpl source) throws RepositoryException;
+ public MultiColumnQuery create(SourceImpl source) throws RepositoryException {
+ // source is either selector or join
+ try {
+ return (MultiColumnQuery) source.accept(new DefaultQOMTreeVisitor() {
+ public Object visit(JoinImpl node, Object data) throws Exception {
+ return create(node);
+ }
+
+ public Object visit(SelectorImpl node, Object data) throws Exception {
+ return MultiColumnQueryAdapter.adapt(
+ create(node), node.getSelectorQName());
+ }
+ }, null);
+ } catch (RepositoryException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new RepositoryException(e);
+ }
+ }
/**
* Creates a multi column query for the given QOM join.
@@ -74,5 +283,11 @@ public interface LuceneQueryFactory {
* @return the multi column query for the given join.
* @throws RepositoryException if an error occurs while creating the query.
*/
- public MultiColumnQuery create(JoinImpl join) throws RepositoryException;
+ public MultiColumnQuery create(JoinImpl join) throws RepositoryException {
+ MultiColumnQuery left = create((SourceImpl) join.getLeft());
+ MultiColumnQuery right = create((SourceImpl) join.getRight());
+ return new JoinQuery(left, right, join.getJoinTypeInstance(),
+ (JoinConditionImpl) join.getJoinCondition(), nsMappings, hmgr);
+ }
+
}
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/QueryObjectModelImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/QueryObjectModelImpl.java?rev=1024259&r1=1024258&r2=1024259&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/QueryObjectModelImpl.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/QueryObjectModelImpl.java Tue Oct 19 15:06:41 2010
@@ -94,7 +94,7 @@ public class QueryObjectModelImpl extend
public QueryResult execute(long offset, long limit)
throws RepositoryException {
SessionImpl session = sessionContext.getSessionImpl();
- LuceneQueryFactory factory = new LuceneQueryFactoryImpl(
+ LuceneQueryFactory factory = new LuceneQueryFactory(
session, index.getContext().getHierarchyManager(),
index.getNamespaceMappings(), index.getTextAnalyzer(),
index.getSynonymProvider(), index.getIndexFormatVersion(),