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(),