JoinQueryEvaluationStep.java
/*******************************************************************************
* Copyright (c) 2021 Eclipse RDF4J contributors.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Distribution License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: BSD-3-Clause
*******************************************************************************/
package org.eclipse.rdf4j.query.algebra.evaluation.impl.evaluationsteps;
import org.eclipse.rdf4j.common.iteration.CloseableIteration;
import org.eclipse.rdf4j.query.BindingSet;
import org.eclipse.rdf4j.query.algebra.Join;
import org.eclipse.rdf4j.query.algebra.Service;
import org.eclipse.rdf4j.query.algebra.TupleExpr;
import org.eclipse.rdf4j.query.algebra.evaluation.EvaluationStrategy;
import org.eclipse.rdf4j.query.algebra.evaluation.QueryEvaluationStep;
import org.eclipse.rdf4j.query.algebra.evaluation.federation.ServiceJoinIterator;
import org.eclipse.rdf4j.query.algebra.evaluation.impl.QueryEvaluationContext;
import org.eclipse.rdf4j.query.algebra.evaluation.iterator.HashJoinIteration;
import org.eclipse.rdf4j.query.algebra.evaluation.iterator.InnerMergeJoinIterator;
import org.eclipse.rdf4j.query.algebra.evaluation.iterator.JoinIterator;
import org.eclipse.rdf4j.query.algebra.helpers.TupleExprs;
public class JoinQueryEvaluationStep implements QueryEvaluationStep {
private final java.util.function.Function<BindingSet, CloseableIteration<BindingSet>> eval;
public JoinQueryEvaluationStep(EvaluationStrategy strategy, Join join, QueryEvaluationContext context) {
// efficient computation of a SERVICE join using vectored evaluation
// TODO maybe we can create a ServiceJoin node already in the parser?
QueryEvaluationStep leftPrepared = strategy.precompile(join.getLeftArg(), context);
QueryEvaluationStep rightPrepared = strategy.precompile(join.getRightArg(), context);
if (join.getRightArg() instanceof Service) {
eval = bindings -> new ServiceJoinIterator(leftPrepared.evaluate(bindings),
(Service) join.getRightArg(), bindings,
strategy);
join.setAlgorithm(ServiceJoinIterator.class.getSimpleName());
} else if (isOutOfScopeForLeftArgBindings(join.getRightArg())) {
String[] joinAttributes = HashJoinIteration.hashJoinAttributeNames(join);
eval = bindings -> new HashJoinIteration(leftPrepared, rightPrepared, bindings, false,
joinAttributes, context);
join.setAlgorithm(HashJoinIteration.class.getSimpleName());
} else if (join.isMergeJoin() && context.getComparator() != null) {
eval = bindings -> InnerMergeJoinIterator.getInstance(leftPrepared, rightPrepared, bindings,
context.getComparator(), context.getValue(join.getOrder().getName()), context);
join.setAlgorithm(InnerMergeJoinIterator.class.getSimpleName());
} else {
eval = bindings -> JoinIterator.getInstance(leftPrepared, rightPrepared, bindings);
join.setAlgorithm(JoinIterator.class.getSimpleName());
}
}
@Override
public CloseableIteration<BindingSet> evaluate(BindingSet bindings) {
return eval.apply(bindings);
}
private static boolean isOutOfScopeForLeftArgBindings(TupleExpr expr) {
return TupleExprs.isVariableScopeChange(expr) || TupleExprs.containsSubquery(expr);
}
}