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/22 17:09:01 UTC
svn commit: r1026361 - in
/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query:
./ lucene/ lucene/constraint/ lucene/join/
Author: jukka
Date: Fri Oct 22 15:09:00 2010
New Revision: 1026361
URL: http://svn.apache.org/viewvc?rev=1026361&view=rev
Log:
JCR-2715: Improved join query performance
Extend LuceneQueryFactory to handle more QOM constraints.
Simplify handling of bind variables.
Improve OperandEvaluator, including its javadocs.
Modified:
jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/ExecutableQuery.java
jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/QueryImpl.java
jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/QueryObjectModelImpl.java
jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/AbstractQueryImpl.java
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/QueryImpl.java
jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/QueryObjectModelImpl.java
jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/constraint/ConstraintBuilder.java
jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/OperandEvaluator.java
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/ExecutableQuery.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/ExecutableQuery.java?rev=1026361&r1=1026360&r2=1026361&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/ExecutableQuery.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/ExecutableQuery.java Fri Oct 22 15:09:00 2010
@@ -16,7 +16,7 @@
*/
package org.apache.jackrabbit.core.query;
-import org.apache.jackrabbit.spi.Name;
+import java.util.Map;
import javax.jcr.RepositoryException;
import javax.jcr.Value;
@@ -45,17 +45,16 @@ public interface ExecutableQuery {
*
* @param varName name of variable in query
* @param value value to bind
- * @throws IllegalArgumentException if <code>varName</code> is not a
- * valid variable in this query.
- * @throws RepositoryException if an error occurs.
+ * @throws RepositoryException if <code>varName</code> is not a
+ * valid variable in this query.
*/
- void bindValue(Name varName, Value value)
- throws IllegalArgumentException, RepositoryException;
+ void bindValue(String varName, Value value) throws RepositoryException;
/**
- * @return the names of the bind variables in this query.
+ * Returns the bind variables of this query.
*
- * @throws RepositoryException if an error occurs.
+ * @return bind variables
*/
- Name[] getBindVariableNames() throws RepositoryException;
+ Map<String, Value> getBindVariables();
+
}
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/QueryImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/QueryImpl.java?rev=1026361&r1=1026360&r2=1026361&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/QueryImpl.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/QueryImpl.java Fri Oct 22 15:09:00 2010
@@ -21,6 +21,7 @@ import static org.apache.jackrabbit.spi.
import static org.apache.jackrabbit.spi.commons.name.NameConstants.NT_QUERY;
import java.text.NumberFormat;
+import java.util.Set;
import javax.jcr.ItemExistsException;
import javax.jcr.ItemNotFoundException;
@@ -37,7 +38,6 @@ import javax.jcr.version.VersionExceptio
import org.apache.jackrabbit.core.session.SessionContext;
import org.apache.jackrabbit.core.session.SessionOperation;
-import org.apache.jackrabbit.spi.Name;
import org.apache.jackrabbit.spi.Path;
import org.apache.jackrabbit.spi.commons.conversion.NameException;
import org.slf4j.Logger;
@@ -211,12 +211,8 @@ public class QueryImpl extends AbstractQ
* {@inheritDoc}
*/
public String[] getBindVariableNames() throws RepositoryException {
- Name[] names = query.getBindVariableNames();
- String[] strNames = new String[names.length];
- for (int i = 0; i < names.length; i++) {
- strNames[i] = sessionContext.getJCRName(names[i]);
- }
- return strNames;
+ Set<String> names = query.getBindVariables().keySet();
+ return names.toArray(new String[names.size()]);
}
/**
@@ -233,7 +229,7 @@ public class QueryImpl extends AbstractQ
throws IllegalArgumentException, RepositoryException {
checkInitialized();
try {
- query.bindValue(sessionContext.getQName(varName), value);
+ query.bindValue(varName, value);
} catch (NameException e) {
throw new RepositoryException(e.getMessage());
}
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/QueryObjectModelImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/QueryObjectModelImpl.java?rev=1026361&r1=1026360&r2=1026361&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/QueryObjectModelImpl.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/QueryObjectModelImpl.java Fri Oct 22 15:09:00 2010
@@ -51,8 +51,6 @@ public class QueryObjectModelImpl extend
*/
protected QueryObjectModelTree qomTree;
- private final Map<String, Value> variables = new HashMap<String, Value>();
-
/**
* {@inheritDoc}
* @throws UnsupportedOperationException always.
@@ -91,19 +89,9 @@ public class QueryObjectModelImpl extend
this.node = node;
this.statement = QueryObjectModelBuilderRegistry.getQueryObjectModelBuilder(language).toString(this);
this.query = handler.createExecutableQuery(sessionContext, qomTree);
- for (Name name : query.getBindVariableNames()) {
- variables.put(sessionContext.getJCRName(name), null);
- }
setInitialized();
}
- @Override
- public void bindValue(String varName, Value value)
- throws IllegalArgumentException, RepositoryException {
- super.bindValue(varName, value);
- variables.put(varName, value);
- }
-
public QueryResult execute() throws RepositoryException {
Source source = getSource();
if (source instanceof Join) {
@@ -111,7 +99,7 @@ public class QueryObjectModelImpl extend
if (JCR_JOIN_TYPE_INNER.equals(join.getJoinType())
&& join.getJoinCondition() instanceof EquiJoinCondition) {
QueryEngine engine =
- new QueryEngine(sessionContext.getSessionImpl(), variables);
+ new QueryEngine(sessionContext.getSessionImpl(), query.getBindVariables());
return engine.execute(
getColumns(), getSource(), getConstraint(),
getOrderings(), offset, limit);
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/AbstractQueryImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/AbstractQueryImpl.java?rev=1026361&r1=1026360&r2=1026361&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/AbstractQueryImpl.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/AbstractQueryImpl.java Fri Oct 22 15:09:00 2010
@@ -16,21 +16,16 @@
*/
package org.apache.jackrabbit.core.query.lucene;
-import org.apache.jackrabbit.core.query.ExecutableQuery;
-import org.apache.jackrabbit.core.query.PropertyTypeRegistry;
-import org.apache.jackrabbit.core.session.SessionContext;
-import org.apache.jackrabbit.spi.Name;
+import java.util.Map;
-import javax.jcr.Value;
import javax.jcr.RepositoryException;
+import javax.jcr.Value;
import javax.jcr.Workspace;
import javax.jcr.query.qom.QueryObjectModelFactory;
-import java.util.Set;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.HashMap;
-import java.util.Collections;
+import org.apache.jackrabbit.core.query.ExecutableQuery;
+import org.apache.jackrabbit.core.query.PropertyTypeRegistry;
+import org.apache.jackrabbit.core.session.SessionContext;
/**
* <code>AbstractQueryImpl</code> provides a base class for executable queries
@@ -59,15 +54,8 @@ public abstract class AbstractQueryImpl
*/
private boolean documentOrder = true;
- /**
- * Set<Name>, where Name is a variable name in the query statement.
- */
- private final Set<Name> variableNames = new HashSet<Name>();
-
- /**
- * Binding of variable name to value. Maps {@link Name} to {@link Value}.
- */
- private final Map<Name, Value> bindValues = new HashMap<Name, Value>();
+ /** Bind variables of this query */
+ private final Map<String, Value> variables;
/**
@@ -79,10 +67,11 @@ public abstract class AbstractQueryImpl
*/
public AbstractQueryImpl(
SessionContext sessionContext, SearchIndex index,
- PropertyTypeRegistry propReg) {
+ PropertyTypeRegistry propReg, Map<String, Value> variables) {
this.sessionContext = sessionContext;
this.index = index;
this.propReg = propReg;
+ this.variables = variables;
}
/**
@@ -122,37 +111,21 @@ public abstract class AbstractQueryImpl
* variable in this query.
* @throws RepositoryException if an error occurs.
*/
- public void bindValue(Name varName, Value value)
+ public void bindValue(String varName, Value value)
throws IllegalArgumentException, RepositoryException {
- if (!variableNames.contains(varName)) {
- throw new IllegalArgumentException("not a valid variable in this query");
+ if (variables.containsKey(varName)) {
+ variables.put(varName, value);
} else {
- bindValues.put(varName, value);
+ throw new IllegalArgumentException(
+ varName + " is not a valid variable in this query");
}
}
/**
* {@inheritDoc}
*/
- public Name[] getBindVariableNames() throws RepositoryException {
- return variableNames.toArray(new Name[variableNames.size()]);
- }
-
- /**
- * Adds a name to the set of variables.
- *
- * @param varName the name of the variable.
- */
- protected void addVariableName(Name varName) {
- variableNames.add(varName);
- }
-
- /**
- * @return an unmodifieable map, which contains the variable names and their
- * respective value.
- */
- protected Map<Name, Value> getBindVariableValues() {
- return Collections.unmodifiableMap(bindValues);
+ public Map<String, Value> getBindVariables() {
+ return variables;
}
/**
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=1026361&r1=1026360&r2=1026361&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 Fri Oct 22 15:09:00 2010
@@ -16,42 +16,70 @@
*/
package org.apache.jackrabbit.core.query.lucene;
+import static javax.jcr.PropertyType.DATE;
+import static javax.jcr.PropertyType.DOUBLE;
+import static javax.jcr.PropertyType.LONG;
+import static javax.jcr.PropertyType.NAME;
+import static javax.jcr.PropertyType.STRING;
+import static javax.jcr.PropertyType.UNDEFINED;
+import static javax.jcr.query.qom.QueryObjectModelConstants.JCR_OPERATOR_EQUAL_TO;
+import static javax.jcr.query.qom.QueryObjectModelConstants.JCR_OPERATOR_GREATER_THAN;
+import static javax.jcr.query.qom.QueryObjectModelConstants.JCR_OPERATOR_GREATER_THAN_OR_EQUAL_TO;
+import static javax.jcr.query.qom.QueryObjectModelConstants.JCR_OPERATOR_LESS_THAN;
+import static javax.jcr.query.qom.QueryObjectModelConstants.JCR_OPERATOR_LESS_THAN_OR_EQUAL_TO;
+import static javax.jcr.query.qom.QueryObjectModelConstants.JCR_OPERATOR_LIKE;
+import static javax.jcr.query.qom.QueryObjectModelConstants.JCR_OPERATOR_NOT_EQUAL_TO;
import static org.apache.jackrabbit.core.query.lucene.FieldNames.PROPERTIES;
import static org.apache.jackrabbit.spi.commons.name.NameConstants.JCR_MIXINTYPES;
import static org.apache.jackrabbit.spi.commons.name.NameConstants.JCR_PRIMARYTYPE;
+import static org.apache.lucene.search.BooleanClause.Occur.MUST;
import static org.apache.lucene.search.BooleanClause.Occur.SHOULD;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
+import javax.jcr.PropertyType;
import javax.jcr.RepositoryException;
+import javax.jcr.UnsupportedRepositoryOperationException;
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.nodetype.PropertyDefinition;
+import javax.jcr.query.qom.And;
+import javax.jcr.query.qom.ChildNode;
+import javax.jcr.query.qom.Comparison;
+import javax.jcr.query.qom.Constraint;
+import javax.jcr.query.qom.DescendantNode;
+import javax.jcr.query.qom.DynamicOperand;
+import javax.jcr.query.qom.FullTextSearch;
+import javax.jcr.query.qom.Not;
+import javax.jcr.query.qom.Or;
+import javax.jcr.query.qom.PropertyExistence;
+import javax.jcr.query.qom.PropertyValue;
+import javax.jcr.query.qom.SameNode;
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.BooleanQuery;
-import org.apache.lucene.search.Query;
import org.apache.jackrabbit.core.HierarchyManager;
import org.apache.jackrabbit.core.SessionImpl;
+import org.apache.jackrabbit.core.query.lucene.join.OperandEvaluator;
import org.apache.jackrabbit.spi.Name;
import org.apache.jackrabbit.spi.commons.conversion.NamePathResolver;
-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.JoinConditionImpl;
+import org.apache.jackrabbit.spi.commons.query.qom.JoinImpl;
import org.apache.jackrabbit.spi.commons.query.qom.PropertyExistenceImpl;
+import org.apache.jackrabbit.spi.commons.query.qom.SelectorImpl;
import org.apache.jackrabbit.spi.commons.query.qom.SourceImpl;
-import org.apache.jackrabbit.spi.commons.query.qom.JoinImpl;
+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.Occur;
+import org.apache.lucene.search.BooleanQuery;
+import org.apache.lucene.search.Query;
/**
* Factory that creates Lucene queries from QOM elements.
@@ -98,10 +126,8 @@ public class LuceneQueryFactory {
*/
private final IndexFormatVersion version;
- /**
- * The Bind Variable values.
- */
- private final Map<Name, Value> bindVariables;
+ /** Operand evaluator */
+ private final OperandEvaluator evaluator;
private final String mixinTypesField;
@@ -123,7 +149,7 @@ public class LuceneQueryFactory {
SessionImpl session, HierarchyManager hmgr,
NamespaceMappings nsMappings, Analyzer analyzer,
SynonymProvider synonymProvider, IndexFormatVersion version,
- Map<Name, Value> bindVariables) throws RepositoryException {
+ Map<String, Value> bindVariables) throws RepositoryException {
this.session = session;
this.ntManager = session.getWorkspace().getNodeTypeManager();
this.hmgr = hmgr;
@@ -132,7 +158,8 @@ public class LuceneQueryFactory {
this.synonymProvider = synonymProvider;
this.version = version;
this.npResolver = NamePathResolverImpl.create(nsMappings);
- this.bindVariables = bindVariables;
+ this.evaluator =
+ new OperandEvaluator(session.getValueFactory(), bindVariables);
this.mixinTypesField = nsMappings.translateName(JCR_MIXINTYPES);
this.primaryTypeField = nsMappings.translateName(JCR_PRIMARYTYPE);
}
@@ -205,20 +232,7 @@ public class LuceneQueryFactory {
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);
- }
+ return parser.parse(evaluator.getValue(expr).getString());
} catch (ParseException e) {
throw new RepositoryException(e);
}
@@ -277,4 +291,154 @@ public class LuceneQueryFactory {
(JoinConditionImpl) join.getJoinCondition(), nsMappings, hmgr);
}
+ public Query create(
+ Constraint constraint, Map<String, NodeType> selectorMap)
+ throws RepositoryException {
+ if (constraint instanceof And) {
+ return getAndQuery((And) constraint, selectorMap);
+ } else if (constraint instanceof Or) {
+ return getOrQuery((Or) constraint, selectorMap);
+ } else if (constraint instanceof Not) {
+ return getNotQuery((Not) constraint, selectorMap);
+ } else if (constraint instanceof PropertyExistence) {
+ return getPropertyExistenceQuery((PropertyExistence) constraint);
+ } else if (constraint instanceof Comparison) {
+ return getComparisonQuery((Comparison) constraint, selectorMap);
+ } else if (constraint instanceof FullTextSearch) {
+ return null; // FIXME
+ } else if (constraint instanceof SameNode) {
+ return null; // FIXME
+ } else if (constraint instanceof ChildNode) {
+ return null; // FIXME
+ } else if (constraint instanceof DescendantNode) {
+ return null; // FIXME
+ } else {
+ throw new UnsupportedRepositoryOperationException(
+ "Unknown constraint type: " + constraint);
+ }
+ }
+
+ private BooleanQuery getAndQuery(
+ And and, Map<String, NodeType> selectorMap)
+ throws RepositoryException {
+ BooleanQuery query = new BooleanQuery();
+ addBooleanConstraint(query, and.getConstraint1(), MUST, selectorMap);
+ addBooleanConstraint(query, and.getConstraint2(), MUST, selectorMap);
+ return query;
+ }
+
+ private BooleanQuery getOrQuery(Or or, Map<String, NodeType> selectorMap)
+ throws RepositoryException {
+ BooleanQuery query = new BooleanQuery();
+ addBooleanConstraint(query, or.getConstraint1(), SHOULD, selectorMap);
+ addBooleanConstraint(query, or.getConstraint2(), SHOULD, selectorMap);
+ return query;
+ }
+
+ private void addBooleanConstraint(
+ BooleanQuery query, Constraint constraint, Occur occur,
+ Map<String, NodeType> selectorMap) throws RepositoryException {
+ if (occur == MUST && constraint instanceof And) {
+ And and = (And) constraint;
+ addBooleanConstraint(query, and.getConstraint1(), occur, selectorMap);
+ addBooleanConstraint(query, and.getConstraint2(), occur, selectorMap);
+ } else if (occur == SHOULD && constraint instanceof Or) {
+ Or or = (Or) constraint;
+ addBooleanConstraint(query, or.getConstraint1(), occur, selectorMap);
+ addBooleanConstraint(query, or.getConstraint2(), occur, selectorMap);
+ } else {
+ query.add(create(constraint, selectorMap), occur);
+ }
+ }
+
+ private NotQuery getNotQuery(Not not, Map<String, NodeType> selectorMap)
+ throws RepositoryException {
+ return new NotQuery(create(not.getConstraint(), selectorMap));
+ }
+
+ private Query getPropertyExistenceQuery(PropertyExistence property)
+ throws RepositoryException {
+ String name = npResolver.getJCRName(session.getQName(
+ property.getPropertyName()));
+ return Util.createMatchAllQuery(name, version);
+ }
+
+ private Query getComparisonQuery(
+ Comparison comparison, Map<String, NodeType> selectorMap)
+ throws RepositoryException {
+ DynamicOperand operand = comparison.getOperand1();
+ if (operand instanceof PropertyValue) {
+ PropertyValue property = (PropertyValue) operand;
+ String field = npResolver.getJCRName(session.getQName(
+ property.getPropertyName()));
+ int type = PropertyType.UNDEFINED;
+ NodeType nt = selectorMap.get(property.getSelectorName());
+ if (nt != null) {
+ for (PropertyDefinition pd : nt.getPropertyDefinitions()) {
+ if (pd.getName().equals(property.getPropertyName())) {
+ type = pd.getRequiredType();
+ }
+ }
+ }
+ return getPropertyValueQuery(
+ field, comparison.getOperator(),
+ evaluator.getValue(comparison.getOperand2()), type);
+ } else {
+ throw new UnsupportedRepositoryOperationException(); // FIXME
+ }
+ }
+
+ private Query getPropertyValueQuery(
+ String field, String operator, Value value, int type)
+ throws RepositoryException {
+ Term term = getTerm(field, getValueString(value, type));
+ if (JCR_OPERATOR_EQUAL_TO.equals(operator)) {
+ return new JackrabbitTermQuery(term);
+ } else if (JCR_OPERATOR_GREATER_THAN.equals(operator)) {
+ return new RangeQuery(term, getTerm(field, "\uFFFF"), false);
+ } else if (JCR_OPERATOR_GREATER_THAN_OR_EQUAL_TO.equals(operator)) {
+ return new RangeQuery(term, getTerm(field, "\uFFFF"), true);
+ } else if (JCR_OPERATOR_LESS_THAN.equals(operator)) {
+ return new RangeQuery(getTerm(field, ""), term, false);
+ } else if (JCR_OPERATOR_LESS_THAN_OR_EQUAL_TO.equals(operator)) {
+ return new RangeQuery(getTerm(field, ""), term, true);
+ } else if (JCR_OPERATOR_NOT_EQUAL_TO.equals(operator)) {
+ BooleanQuery or = new BooleanQuery();
+ or.add(new RangeQuery(getTerm(field, ""), term, false), SHOULD);
+ or.add(new RangeQuery(term, getTerm(field, "\uFFFF"), false), SHOULD);
+ return or;
+ } else if (JCR_OPERATOR_LIKE.equals(operator)) {
+ throw new UnsupportedRepositoryOperationException(); // FIXME
+ } else {
+ throw new UnsupportedRepositoryOperationException(); // FIXME
+ }
+ }
+
+ private Term getTerm(String field, String value) {
+ return new Term(PROPERTIES, FieldNames.createNamedValue(field, value));
+ }
+
+ private String getValueString(Value value, int type)
+ throws RepositoryException {
+ switch (value.getType()) {
+ case DATE:
+ return DateField.dateToString(value.getDate().getTime());
+ case DOUBLE:
+ return DoubleField.doubleToString(value.getDouble());
+ case LONG:
+ return LongField.longToString(value.getLong());
+ case NAME:
+ return npResolver.getJCRName(session.getQName(value.getString()));
+ default:
+ String string = value.getString();
+ if (type != UNDEFINED && type != STRING) {
+ return getValueString(
+ session.getValueFactory().createValue(string, type),
+ UNDEFINED);
+ } else {
+ return string;
+ }
+ }
+ }
+
}
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/QueryImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/QueryImpl.java?rev=1026361&r1=1026360&r2=1026361&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/QueryImpl.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/QueryImpl.java Fri Oct 22 15:09:00 2010
@@ -16,10 +16,12 @@
*/
package org.apache.jackrabbit.core.query.lucene;
+import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import javax.jcr.RepositoryException;
+import javax.jcr.Value;
import javax.jcr.Workspace;
import javax.jcr.nodetype.PropertyDefinition;
import javax.jcr.query.InvalidQueryException;
@@ -86,7 +88,8 @@ public class QueryImpl extends AbstractQ
SessionContext sessionContext, SearchIndex index,
PropertyTypeRegistry propReg, String statement, String language,
QueryNodeFactory factory) throws InvalidQueryException {
- super(sessionContext, index, propReg);
+ super(sessionContext, index, propReg,
+ Collections.<String, Value>emptyMap());
// parse query according to language
// build query tree using the passed factory
this.root = QueryParser.parse(
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=1026361&r1=1026360&r2=1026361&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 Fri Oct 22 15:09:00 2010
@@ -17,9 +17,12 @@
package org.apache.jackrabbit.core.query.lucene;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import javax.jcr.RepositoryException;
+import javax.jcr.Value;
import javax.jcr.nodetype.PropertyDefinition;
import javax.jcr.query.InvalidQueryException;
import javax.jcr.query.QueryResult;
@@ -63,10 +66,9 @@ public class QueryObjectModelImpl extend
SessionContext sessionContext, SearchIndex index,
PropertyTypeRegistry propReg, QueryObjectModelTree qomTree)
throws InvalidQueryException {
- super(sessionContext, index, propReg);
+ super(sessionContext, index, propReg, extractBindVariables(qomTree));
this.qomTree = qomTree;
checkNodeTypes();
- extractBindVariableNames();
}
/**
@@ -98,13 +100,13 @@ public class QueryObjectModelImpl extend
session, index.getContext().getHierarchyManager(),
index.getNamespaceMappings(), index.getTextAnalyzer(),
index.getSynonymProvider(), index.getIndexFormatVersion(),
- getBindVariableValues());
+ getBindVariables());
MultiColumnQuery query = factory.create(qomTree.getSource());
if (qomTree.getConstraint() != null) {
Constraint c = ConstraintBuilder.create(qomTree.getConstraint(),
- getBindVariableValues(), qomTree.getSource().getSelectors(),
+ getBindVariables(), qomTree.getSource().getSelectors(),
factory, session.getValueFactory());
query = new FilterMultiColumnQuery(query, c);
}
@@ -145,17 +147,20 @@ public class QueryObjectModelImpl extend
* Extracts all {@link BindVariableValueImpl} from the {@link #qomTree}
* and adds it to the set of known variable names.
*/
- private void extractBindVariableNames() {
+ private static Map<String, Value> extractBindVariables(
+ QueryObjectModelTree qomTree) {
+ final Map<String, Value> variables = new HashMap<String, Value>();
try {
qomTree.accept(new DefaultTraversingQOMTreeVisitor() {
public Object visit(BindVariableValueImpl node, Object data) {
- addVariableName(node.getBindVariableQName());
+ variables.put(node.getBindVariableName(), null);
return data;
}
}, null);
} catch (Exception e) {
// will never happen
}
+ return variables;
}
/**
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/constraint/ConstraintBuilder.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/constraint/ConstraintBuilder.java?rev=1026361&r1=1026360&r2=1026361&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/constraint/ConstraintBuilder.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/constraint/ConstraintBuilder.java Fri Oct 22 15:09:00 2010
@@ -73,7 +73,7 @@ public class ConstraintBuilder {
* constraint.
*/
public static Constraint create(ConstraintImpl constraint,
- Map<Name, Value> bindVariableValues,
+ Map<String, Value> bindVariableValues,
SelectorImpl[] selectors,
LuceneQueryFactory factory,
ValueFactory vf)
@@ -96,7 +96,7 @@ public class ConstraintBuilder {
/**
* The bind variables and their values.
*/
- private final Map<Name, Value> bindVariableValues;
+ private final Map<String, Value> bindVariableValues;
/**
* The selectors of the query.
@@ -121,7 +121,7 @@ public class ConstraintBuilder {
* @param factory the lucene query factory.
* @param vf the value factory of the current session.
*/
- Visitor(Map<Name, Value> bindVariableValues,
+ Visitor(Map<String, Value> bindVariableValues,
SelectorImpl[] selectors,
LuceneQueryFactory factory,
ValueFactory vf) {
@@ -140,7 +140,14 @@ public class ConstraintBuilder {
public Object visit(BindVariableValueImpl node, Object data)
throws Exception {
- return bindVariableValues.get(node.getBindVariableQName());
+ String name = node.getBindVariableName();
+ Value value = bindVariableValues.get(name);
+ if (value != null) {
+ return value;
+ } else {
+ throw new RepositoryException(
+ "No value specified for bind variable " + name);
+ }
}
public Object visit(ChildNodeImpl node, Object data) throws Exception {
Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/OperandEvaluator.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/OperandEvaluator.java?rev=1026361&r1=1026360&r2=1026361&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/OperandEvaluator.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/query/lucene/join/OperandEvaluator.java Fri Oct 22 15:09:00 2010
@@ -38,28 +38,79 @@ import javax.jcr.query.qom.NodeLocalName
import javax.jcr.query.qom.NodeName;
import javax.jcr.query.qom.Operand;
import javax.jcr.query.qom.PropertyValue;
+import javax.jcr.query.qom.StaticOperand;
import javax.jcr.query.qom.UpperCase;
-class OperandEvaluator {
+/**
+ * Evaluator of QOM {@link Operand operands}. This class evaluates operands
+ * in the context of a {@link ValueFactory value factory}, a set of bind
+ * variables and possibly a query result row.
+ */
+public class OperandEvaluator {
+ /** Value factory */
private final ValueFactory factory;
+ /** Bind variables */
private final Map<String, Value> variables;
+ /**
+ * Creates an operand evaluator for the given value factory and set of
+ * bind variables.
+ *
+ * @param factory value factory
+ * @param variables bind variables
+ */
public OperandEvaluator(
ValueFactory factory, Map<String, Value> variables) {
this.factory = factory;
this.variables = variables;
}
+ /**
+ * Returns the value of the given static operand
+ * ({@link Literal literal} or {@link BindVariableValue bind variable}).
+ *
+ * @param operand static operand to be evaluated
+ * @return evaluated value
+ * @throws RepositoryException if a named bind variable is not found,
+ * or if the operand type is unknown
+ */
+ public Value getValue(StaticOperand operand) throws RepositoryException {
+ if (operand instanceof Literal) {
+ Literal literal = (Literal) operand;
+ return literal.getLiteralValue();
+ } else if (operand instanceof BindVariableValue) {
+ BindVariableValue bvv = (BindVariableValue) operand;
+ Value value = variables.get(bvv.getBindVariableName());
+ if (value != null) {
+ return value;
+ } else {
+ throw new RepositoryException(
+ "Unknown bind variable: " + bvv.getBindVariableName());
+ }
+ } else {
+ throw new UnsupportedRepositoryOperationException(
+ "Unknown static operand type: " + operand);
+ }
+ }
+
+ /**
+ * Returns the value of the given operand in the context of the given row.
+ * This is a convenience method that uses a somewhat lossy best-effort
+ * mapping to evaluate multi-valued operands to a single value. Use the
+ * {@link #getValues(Operand, Row)} method for more accurate results.
+ *
+ * @param operand operand to be evaluated
+ * @param row query result row
+ * @return evaluated value
+ * @throws RepositoryException
+ */
public Value getValue(Operand operand, Row row) throws RepositoryException {
Value[] values = getValues(operand, row);
- switch (values.length) {
- case 0:
- return factory.createValue("");
- case 1:
+ if (values.length == 1) {
return values[0];
- default:
+ } else {
StringBuilder builder = new StringBuilder();
for (int i = 0; i < values.length; i++) {
if (i > 0) {
@@ -72,34 +123,36 @@ class OperandEvaluator {
}
/**
- * Evaluates the given operand against the given row.
+ * Evaluates the given operand in the context of the given row.
*
- * @param operand operand
- * @param row row
+ * @param operand operand to be evaluated
+ * @param row query result row
* @return values of the operand at the given row
* @throws RepositoryException if the operand can't be evaluated
*/
public Value[] getValues(Operand operand, Row row)
throws RepositoryException {
- if (operand instanceof BindVariableValue) {
- return getBindVariableValues((BindVariableValue) operand);
+ if (operand instanceof StaticOperand) {
+ StaticOperand so = (StaticOperand) operand;
+ return new Value[] { getValue(so) };
} else if (operand instanceof FullTextSearchScore) {
- return getFullTextSearchScoreValues(
- (FullTextSearchScore) operand, row);
+ FullTextSearchScore ftss = (FullTextSearchScore) operand;
+ double score = row.getScore(ftss.getSelectorName());
+ return new Value[] { factory.createValue(score) };
+ } else if (operand instanceof NodeName) {
+ NodeName nn = (NodeName) operand;
+ Node node = row.getNode(nn.getSelectorName());
+ return new Value[] { factory.createValue(node.getName(), NAME) };
} else if (operand instanceof Length) {
return getLengthValues((Length) operand, row);
- } else if (operand instanceof Literal) {
- return getLiteralValues((Literal) operand);
} else if (operand instanceof LowerCase) {
return getLowerCaseValues((LowerCase) operand, row);
+ } else if (operand instanceof UpperCase) {
+ return getUpperCaseValues((UpperCase) operand, row);
} else if (operand instanceof NodeLocalName) {
return getNodeLocalNameValues((NodeLocalName) operand, row);
- } else if (operand instanceof NodeName) {
- return getNodeNameValues((NodeName) operand, row);
} else if (operand instanceof PropertyValue) {
return getPropertyValues((PropertyValue) operand, row);
- } else if (operand instanceof UpperCase) {
- return getUpperCaseValues((UpperCase) operand, row);
} else {
throw new UnsupportedRepositoryOperationException(
"Unknown operand type: " + operand);
@@ -107,35 +160,6 @@ class OperandEvaluator {
}
/**
- * Returns the value of the given variable value operand at the given row.
- *
- * @param operand variable value operand
- * @return value of the operand at the given row
- */
- private Value[] getBindVariableValues(BindVariableValue operand) {
- Value value = variables.get(operand.getBindVariableName());
- if (value != null) {
- return new Value[] { value };
- } else {
- return new Value[0];
- }
- }
-
- /**
- * Returns the value of the given search score operand at the given row.
- *
- * @param operand search score operand
- * @param row row
- * @return value of the operand at the given row
- * @throws RepositoryException if the operand can't be evaluated
- */
- private Value[] getFullTextSearchScoreValues(
- FullTextSearchScore operand, Row row) throws RepositoryException {
- double score = row.getScore(operand.getSelectorName());
- return new Value[] { factory.createValue(score) };
- }
-
- /**
* Returns the values of the given value length operand at the given row.
*
* @see #getProperty(PropertyValue, Row)
@@ -163,16 +187,6 @@ class OperandEvaluator {
}
/**
- * Returns the value of the given literal value operand.
- *
- * @param operand literal value operand
- * @return value of the operand
- */
- private Value[] getLiteralValues(Literal operand) {
- return new Value[] { operand.getLiteralValue() };
- }
-
- /**
* Returns the values of the given lower case operand at the given row.
*
* @param operand lower case operand
@@ -194,35 +208,42 @@ class OperandEvaluator {
}
/**
- * Returns the value of the given local name operand at the given row.
+ * Returns the values of the given upper case operand at the given row.
*
- * @param operand local name operand
+ * @param operand upper case operand
* @param row row
- * @return value of the operand at the given row
+ * @return values of the operand at the given row
* @throws RepositoryException if the operand can't be evaluated
*/
- private Value[] getNodeLocalNameValues(NodeLocalName operand, Row row)
+ private Value[] getUpperCaseValues(UpperCase operand, Row row)
throws RepositoryException {
- String name = row.getNode(operand.getSelectorName()).getName();
- int colon = name.indexOf(':');
- if (colon != -1) {
- name = name.substring(colon + 1);
+ Value[] values = getValues(operand.getOperand(), row);
+ for (int i = 0; i < values.length; i++) {
+ String value = values[i].getString();
+ String upper = value.toUpperCase(ENGLISH);
+ if (!value.equals(upper)) {
+ values[i] = factory.createValue(upper);
+ }
}
- return new Value[] { factory.createValue(name, NAME) };
+ return values;
}
/**
- * Returns the value of the given node name operand at the given row.
+ * Returns the value of the given local name operand at the given row.
*
- * @param operand node name operand
+ * @param operand local name operand
* @param row row
* @return value of the operand at the given row
* @throws RepositoryException if the operand can't be evaluated
*/
- private Value[] getNodeNameValues(NodeName operand, Row row)
+ private Value[] getNodeLocalNameValues(NodeLocalName operand, Row row)
throws RepositoryException {
- Node node = row.getNode(operand.getSelectorName());
- return new Value[] { factory.createValue(node.getName(), NAME) };
+ String name = row.getNode(operand.getSelectorName()).getName();
+ int colon = name.indexOf(':');
+ if (colon != -1) {
+ name = name.substring(colon + 1);
+ }
+ return new Value[] { factory.createValue(name, NAME) };
}
/**
@@ -247,27 +268,6 @@ class OperandEvaluator {
}
/**
- * Returns the values of the given upper case operand at the given row.
- *
- * @param operand upper case operand
- * @param row row
- * @return values of the operand at the given row
- * @throws RepositoryException if the operand can't be evaluated
- */
- private Value[] getUpperCaseValues(UpperCase operand, Row row)
- throws RepositoryException {
- Value[] values = getValues(operand.getOperand(), row);
- for (int i = 0; i < values.length; i++) {
- String value = values[i].getString();
- String upper = value.toLowerCase(ENGLISH);
- if (!value.equals(upper)) {
- values[i] = factory.createValue(upper);
- }
- }
- return values;
- }
-
- /**
* Returns the identified property from the given row. This method
* is used by both the {@link #getValue(Length, Row)} and the
* {@link #getValue(PropertyValue, Row)} methods to access properties.