blob: 93dc80dfde0004902eaac28afe0e41d72f9085e8 [file] [log] [blame]
package org.apache.rya.indexing.external.matching;
/*
* 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.
*/
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.eclipse.rdf4j.query.algebra.Filter;
import org.eclipse.rdf4j.query.algebra.Join;
import org.eclipse.rdf4j.query.algebra.LeftJoin;
import org.eclipse.rdf4j.query.algebra.QueryModelNode;
import org.eclipse.rdf4j.query.algebra.TupleExpr;
import com.google.common.collect.Lists;
/**
* This class converts a given collection of {@link QueryModelNode}s into a
* {@link TupleExpr}. The primary purpose of this class is to reconstruct a
* TupleExpr representation of a {@link QuerySegment} from its List view.
*
*/
public class QueryNodesToTupleExpr {
private List<QueryModelNode> queryNodes;
private Set<Filter> filters;
public QueryNodesToTupleExpr(List<QueryModelNode> queryNodes, Set<Filter> filters) {
this.queryNodes = queryNodes;
this.filters = filters;
}
/**
*
* @return - a TupleExprAndNodes object that consists of the the TupleExpr
* representation of the List of QueryModelNodes and the nodes used
* to build the TupleExpr.
*/
public TupleExprAndNodes getTupleAndNodes() {
List<QueryModelNode> nodeCopy = new ArrayList<>();
Set<Filter> setCopy = new HashSet<>();
for (QueryModelNode q : queryNodes) {
nodeCopy.add(q.clone());
}
for (Filter f : filters) {
setCopy.add(f.clone());
}
TupleExpr te = buildQuery(nodeCopy, setCopy);
return new TupleExprAndNodes(te, nodeCopy, setCopy);
}
private TupleExpr buildQuery(List<QueryModelNode> queryNodes, Set<Filter> filters) {
List<Filter> chain = getFilterChain(filters);
return getNewJoin(queryNodes, chain);
}
// chain filters together and return front and back of chain
private static List<Filter> getFilterChain(Set<Filter> filters) {
final List<Filter> filterTopBottom = Lists.newArrayList();
Filter filterChainTop = null;
Filter filterChainBottom = null;
for (final Filter filter : filters) {
if (filterChainTop == null) {
filterChainTop = filter;
filter.setParentNode(null);
} else if (filterChainBottom == null) {
filterChainBottom = filter;
filterChainTop.setArg(filterChainBottom);
} else {
filterChainBottom.setArg(filter);
filterChainBottom = filter;
}
}
if (filterChainTop != null) {
filterTopBottom.add(filterChainTop);
}
if (filterChainBottom != null) {
filterTopBottom.add(filterChainBottom);
}
return filterTopBottom;
}
// build newJoin node given remaining joinArgs and chain of filters
private static TupleExpr getNewJoin(List<QueryModelNode> args, List<Filter> filterChain) {
TupleExpr newJoin;
TupleExpr tempJoin;
final List<TupleExpr> joinArgs = Lists.newArrayList();
for (QueryModelNode q : args) {
if (q instanceof TupleExpr) {
joinArgs.add(0, (TupleExpr) q);
} else {
throw new IllegalArgumentException("Invalid query node!");
}
}
if (joinArgs.size() > 1) {
TupleExpr left = joinArgs.remove(0);
TupleExpr right = joinArgs.remove(0);
tempJoin = getJoin(left, right);
for (int i = joinArgs.size() - 1; i >= 0; i--) {
tempJoin = getJoin(tempJoin, joinArgs.get(i));
}
if (filterChain.size() == 0) {
newJoin = tempJoin;
} else if (filterChain.size() == 1) {
newJoin = filterChain.get(0);
((Filter) newJoin).setArg(tempJoin);
} else {
newJoin = filterChain.get(0);
filterChain.get(1).setArg(tempJoin);
}
} else if (joinArgs.size() == 1) {
tempJoin = joinArgs.get(0);
if (filterChain.size() == 0) {
newJoin = tempJoin;
} else if (filterChain.size() == 1) {
newJoin = filterChain.get(0);
((Filter) newJoin).setArg(tempJoin);
} else {
newJoin = filterChain.get(0);
filterChain.get(1).setArg(tempJoin);
}
} else {
throw new IllegalStateException("JoinArgs size cannot be zero.");
}
return newJoin;
}
private static TupleExpr getJoin(TupleExpr oldJoin, TupleExpr newArg) {
if (newArg instanceof FlattenedOptional) {
return new LeftJoin(oldJoin, ((FlattenedOptional) newArg).getRightArg());
} else {
return new Join(oldJoin, newArg);
}
}
public static class TupleExprAndNodes {
private TupleExpr te;
private List<QueryModelNode> nodes;
private Set<Filter> filters;
public TupleExprAndNodes(TupleExpr te, List<QueryModelNode> nodes, Set<Filter> filters) {
this.te = te;
this.nodes = nodes;
this.filters = filters;
}
public TupleExpr getTupleExpr() {
return te;
}
public List<QueryModelNode> getNodes() {
return nodes;
}
public Set<Filter> getFilters() {
return filters;
}
@Override
public String toString() {
return "Query: " + te + " Nodes: " + nodes;
}
}
}