Skip to content

Commit

Permalink
JCR-2852: Support multi-selector OR constraints in join queries
Browse files Browse the repository at this point in the history
Patch by Alex Parvulescu

git-svn-id: https://svn.apache.org/repos/asf/jackrabbit/trunk@1080186 13f79535-47bb-0310-9956-ffa450edef68
  • Loading branch information
jukka committed Mar 10, 2011
1 parent 2506b7a commit 37ee126
Show file tree
Hide file tree
Showing 9 changed files with 328 additions and 92 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package org.apache.jackrabbit.core.query.lucene.join;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
Expand Down Expand Up @@ -59,7 +60,7 @@ public Set<String> getRightValues(Row row) throws RepositoryException {
}

@Override
public List<Constraint> getRightJoinConstraints(List<Row> leftRows)
public List<Constraint> getRightJoinConstraints(Collection<Row> leftRows)
throws RepositoryException {
Set<String> paths = new HashSet<String>();
for (Row row : leftRows) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
/*
* 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.core.query.lucene.join;

import java.util.ArrayList;
import java.util.List;

import javax.jcr.RepositoryException;
import javax.jcr.query.qom.Constraint;
import javax.jcr.query.qom.Or;
import javax.jcr.query.qom.QueryObjectModelFactory;

class ConstraintSplitInfo {

private final QueryObjectModelFactory factory;

private final List<Constraint> leftConstraints = new ArrayList<Constraint>();

private final List<Constraint> rightConstraints = new ArrayList<Constraint>();

private boolean isMultiple;

private final List<ConstraintSplitInfo> innerConstraints = new ArrayList<ConstraintSplitInfo>();

public ConstraintSplitInfo(QueryObjectModelFactory factory) {
this.factory = factory;
this.isMultiple = false;
}

private ConstraintSplitInfo(QueryObjectModelFactory factory,
List<Constraint> leftConstraints, List<Constraint> rightConstraints) {
this.factory = factory;
this.isMultiple = false;
this.leftConstraints.addAll(leftConstraints);
this.rightConstraints.addAll(rightConstraints);
}

public void addLeftConstraint(Constraint c) {
if (isMultiple) {
for (ConstraintSplitInfo csi : innerConstraints) {
csi.addLeftConstraint(c);
}
return;
}
leftConstraints.add(c);
}

public void addRightConstraint(Constraint c) {
if (isMultiple) {
for (ConstraintSplitInfo csi : innerConstraints) {
csi.addRightConstraint(c);
}
return;
}
rightConstraints.add(c);
}

public void split(Or or) {
if (isMultiple) {
for (ConstraintSplitInfo csi : innerConstraints) {
csi.split(or);
}
return;
}

this.isMultiple = true;

ConstraintSplitInfo csi1 = new ConstraintSplitInfo(factory,
leftConstraints, rightConstraints);
csi1.addLeftConstraint(or.getConstraint1());
this.innerConstraints.add(csi1);

ConstraintSplitInfo csi2 = new ConstraintSplitInfo(factory,
leftConstraints, rightConstraints);
csi2.addLeftConstraint(or.getConstraint2());
this.innerConstraints.add(csi2);

// would null be better?
this.leftConstraints.clear();
this.rightConstraints.clear();
}

public boolean isMultiple() {
return isMultiple;
}

public List<ConstraintSplitInfo> getInnerConstraints() {
return innerConstraints;
}

/**
* @return the left constraint
*/
public Constraint getLeftConstraint() throws RepositoryException {
return Constraints.and(factory, leftConstraints);
}

/**
* @return the right constraint
*/
public Constraint getRightConstraint() throws RepositoryException {
return Constraints.and(factory, rightConstraints);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,8 @@
*/
package org.apache.jackrabbit.core.query.lucene.join;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.jcr.RepositoryException;
Expand All @@ -45,15 +43,17 @@
import javax.jcr.query.qom.UpperCase;

/**
* Returns a mapped constraint that only refers to the given set of
* selectors. The returned constraint is guaranteed to match an as small
* as possible superset of the node tuples matched by the given original
* constraints.
* Returns a mapped constraint that only refers to the given set of selectors.
* The returned constraint is guaranteed to match an as small as possible
* superset of the node tuples matched by the given original constraints.
*
* @param constraint original constraint
* @param selectors target selectors
* @param constraint
* original constraint
* @param selectors
* target selectors
* @return mapped constraint
* @throws RepositoryException if the constraint mapping fails
* @throws RepositoryException
* if the constraint mapping fails
*/
class ConstraintSplitter {

Expand All @@ -63,64 +63,55 @@ class ConstraintSplitter {

private final Set<String> rightSelectors;

private final List<Constraint> leftConstraints =
new ArrayList<Constraint>();
private final ConstraintSplitInfo constraintSplitInfo;

private final List<Constraint> rightConstraints =
new ArrayList<Constraint>();

public ConstraintSplitter(
Constraint constraint, QueryObjectModelFactory factory,
Set<String> leftSelectors, Set<String> rightSelectors)
throws RepositoryException {
public ConstraintSplitter(Constraint constraint,
QueryObjectModelFactory factory, Set<String> leftSelectors,
Set<String> rightSelectors) throws RepositoryException {
this.factory = factory;
this.leftSelectors = leftSelectors;
this.rightSelectors = rightSelectors;
constraintSplitInfo = new ConstraintSplitInfo(this.factory);

if (constraint != null) {
split(constraint);
}
}

/**
* @return the left constraint
*/
public Constraint getLeftConstraint() throws RepositoryException {
return Constraints.and(factory, leftConstraints);
}

/**
* @return the right constraint
*/
public Constraint getRightConstraint() throws RepositoryException {
return Constraints.and(factory, rightConstraints);
}

private void split(Constraint constraint) throws RepositoryException {
if (constraint instanceof Not) {
splitNot((Not) constraint);
} else if (constraint instanceof And) {
And and = (And) constraint;
split(and.getConstraint1());
split(and.getConstraint2());
} else if (constraint instanceof Or) {
if (isReferencingBothSides(getSelectorNames(constraint))) {
constraintSplitInfo.split((Or) constraint);
} else {
splitBySelectors(constraint, getSelectorNames(constraint));
}
} else {
splitBySelectors(constraint, getSelectorNames(constraint));
}
}

private boolean isReferencingBothSides(Set<String> selectors) {
return !leftSelectors.containsAll(selectors)
&& !rightSelectors.containsAll(selectors);
}

private void splitNot(Not not) throws RepositoryException {
Constraint constraint = not.getConstraint();
if (constraint instanceof Not) {
split(((Not) constraint).getConstraint());
} else if (constraint instanceof And) {
And and = (And) constraint;
split(factory.or(
factory.not(and.getConstraint1()),
split(factory.or(factory.not(and.getConstraint1()),
factory.not(and.getConstraint2())));
} else if (constraint instanceof Or) {
Or or = (Or) constraint;
split(factory.and(
factory.not(or.getConstraint1()),
split(factory.and(factory.not(or.getConstraint1()),
factory.not(or.getConstraint2())));
} else {
splitBySelectors(not, getSelectorNames(constraint));
Expand All @@ -130,23 +121,24 @@ private void splitNot(Not not) throws RepositoryException {
private void splitBySelectors(Constraint constraint, Set<String> selectors)
throws UnsupportedRepositoryOperationException {
if (leftSelectors.containsAll(selectors)) {
leftConstraints.add(constraint);
constraintSplitInfo.addLeftConstraint(constraint);
} else if (rightSelectors.containsAll(selectors)) {
rightConstraints.add(constraint);
constraintSplitInfo.addRightConstraint(constraint);
} else {
throw new UnsupportedRepositoryOperationException(
"Unable to split a constraint that references"
+ " both sides of a join: " + constraint);
+ " both sides of a join: " + constraint);
}
}

/**
* Returns the names of the selectors referenced by the given constraint.
*
* @param constraint constraint
* @param constraint
* constraint
* @return referenced selector names
* @throws UnsupportedRepositoryOperationException
* if the constraint type is unknown
* if the constraint type is unknown
*/
private Set<String> getSelectorNames(Constraint constraint)
throws UnsupportedRepositoryOperationException {
Expand Down Expand Up @@ -184,14 +176,16 @@ private Set<String> getSelectorNames(Constraint constraint)
}

/**
* Returns the combined set of selector names referenced by the given
* two constraint.
* Returns the combined set of selector names referenced by the given two
* constraint.
*
* @param a first constraint
* @param b second constraint
* @param a
* first constraint
* @param b
* second constraint
* @return selector names
* @throws UnsupportedRepositoryOperationException
* if the constraint types are unknown
* if the constraint types are unknown
*/
private Set<String> getSelectorNames(Constraint a, Constraint b)
throws UnsupportedRepositoryOperationException {
Expand All @@ -204,10 +198,11 @@ private Set<String> getSelectorNames(Constraint a, Constraint b)
/**
* Returns the selector name referenced by the given dynamic operand.
*
* @param operand dynamic operand
* @param operand
* dynamic operand
* @return selector name
* @throws UnsupportedRepositoryOperationException
* if the operand type is unknown
* if the operand type is unknown
*/
private String getSelectorName(DynamicOperand operand)
throws UnsupportedRepositoryOperationException {
Expand Down Expand Up @@ -238,4 +233,8 @@ private String getSelectorName(DynamicOperand operand)
}
}

public ConstraintSplitInfo getConstraintSplitInfo() {
return constraintSplitInfo;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package org.apache.jackrabbit.core.query.lucene.join;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
Expand Down Expand Up @@ -59,7 +60,7 @@ public Set<String> getRightValues(Row row) throws RepositoryException {
}

@Override
public List<Constraint> getRightJoinConstraints(List<Row> leftRows)
public List<Constraint> getRightJoinConstraints(Collection<Row> leftRows)
throws RepositoryException {
Set<String> paths = new HashSet<String>();
for (Row row : leftRows) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import static javax.jcr.query.qom.QueryObjectModelConstants.JCR_OPERATOR_EQUAL_TO;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
Expand Down Expand Up @@ -76,7 +77,7 @@ public Set<String> getRightValues(Row row) throws RepositoryException {
}

@Override
public List<Constraint> getRightJoinConstraints(List<Row> leftRows)
public List<Constraint> getRightJoinConstraints(Collection<Row> leftRows)
throws RepositoryException {
Map<String, Literal> literals = new HashMap<String, Literal>();
for (Row leftRow : leftRows) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import static javax.jcr.query.qom.QueryObjectModelConstants.JCR_JOIN_TYPE_LEFT_OUTER;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashSet;
Expand Down Expand Up @@ -224,7 +225,7 @@ public abstract Set<String> getLeftValues(Row row)
public abstract Set<String> getRightValues(Row row)
throws RepositoryException;

public abstract List<Constraint> getRightJoinConstraints(List<Row> leftRows)
public abstract List<Constraint> getRightJoinConstraints(Collection<Row> leftRows)
throws RepositoryException;

}
Loading

0 comments on commit 37ee126

Please sign in to comment.