All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.eclipse.rdf4j.sail.federation.evaluation.FederationStrategy Maven / Gradle / Ivy

Go to download

The Federation SAIL allows multiple datasets to be virtually combined into a single dataset. The Federation SAIL combines multiple RDF stores that may exist on a remote server or are embedded in the same JVM. The Federation uses query optimizations to distribute sections of the query to different members based on the data contained in each of the members. These results are then joined together within the federation to provide the same result as if all the data was co-located within a single repository.

There is a newer version: 4.0.0-M1
Show newest version
/*******************************************************************************
 * Copyright (c) 2015 Eclipse RDF4J contributors, Aduna, and others.
 * 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.
 *******************************************************************************/
package org.eclipse.rdf4j.sail.federation.evaluation;

import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.Executor;

import org.eclipse.rdf4j.common.iteration.CloseableIteration;
import org.eclipse.rdf4j.common.iteration.UnionIteration;
import org.eclipse.rdf4j.query.BindingSet;
import org.eclipse.rdf4j.query.Dataset;
import org.eclipse.rdf4j.query.QueryEvaluationException;
import org.eclipse.rdf4j.query.algebra.Join;
import org.eclipse.rdf4j.query.algebra.LeftJoin;
import org.eclipse.rdf4j.query.algebra.TupleExpr;
import org.eclipse.rdf4j.query.algebra.Union;
import org.eclipse.rdf4j.query.algebra.evaluation.EvaluationStrategy;
import org.eclipse.rdf4j.query.algebra.evaluation.TripleSource;
import org.eclipse.rdf4j.query.algebra.evaluation.federation.FederatedServiceResolver;
import org.eclipse.rdf4j.query.algebra.evaluation.impl.StrictEvaluationStrategy;
import org.eclipse.rdf4j.query.algebra.evaluation.iterator.BadlyDesignedLeftJoinIterator;
import org.eclipse.rdf4j.query.algebra.evaluation.iterator.HashJoinIteration;
import org.eclipse.rdf4j.query.algebra.helpers.TupleExprs;
import org.eclipse.rdf4j.sail.federation.algebra.NaryJoin;
import org.eclipse.rdf4j.sail.federation.algebra.OwnedTupleExpr;

/**
 * Evaluates Join, LeftJoin and Union in parallel and only evaluate if {@link OwnedTupleExpr} is the given member.
 *
 * @see ParallelJoinCursor
 * @see ParallelLeftJoinCursor
 * @author James Leigh
 */
public class FederationStrategy extends StrictEvaluationStrategy {

	private final Executor executor;

	public FederationStrategy(Executor executor, TripleSource tripleSource, Dataset dataset,
			FederatedServiceResolver serviceManager) {
		super(tripleSource, dataset, serviceManager);
		this.executor = executor;
	}

	@Override
	public CloseableIteration evaluate(TupleExpr expr, BindingSet bindings)
			throws QueryEvaluationException {
		CloseableIteration result;
		if (expr instanceof NaryJoin) {
			result = evaluate((NaryJoin) expr, bindings);
		} else if (expr instanceof OwnedTupleExpr) {
			result = evaluate((OwnedTupleExpr) expr, bindings);
		} else {
			result = super.evaluate(expr, bindings);
		}
		return result;
	}

	@Override
	public CloseableIteration evaluate(Join join, BindingSet bindings)
			throws QueryEvaluationException {
		CloseableIteration result = evaluate(join.getLeftArg(), bindings);
		for (int i = 1, n = 2; i < n; i++) {
			result = new ParallelJoinCursor(this, result, join.getRightArg()); // NOPMD
			executor.execute((Runnable) result);
		}
		return result;
	}

	public CloseableIteration evaluate(NaryJoin join, BindingSet bindings)
			throws QueryEvaluationException {
		assert join.getNumberOfArguments() > 0;
		CloseableIteration result = evaluate(join.getArg(0), bindings);
		Set collectedBindingNames = new HashSet<>();
		collectedBindingNames.addAll(join.getArg(0).getBindingNames());
		for (int i = 1, n = join.getNumberOfArguments(); i < n; i++) {

			TupleExpr rightArg = join.getArg(i);
			if (TupleExprs.containsSubquery(rightArg)
					|| (rightArg instanceof OwnedTupleExpr && ((OwnedTupleExpr) rightArg).hasQuery())) {
				TupleExpr leftArg = join.getArg(i - 1);
				collectedBindingNames.addAll(leftArg.getBindingNames());
				result = new HashJoinIteration(this, result, collectedBindingNames, evaluate(rightArg, bindings),
						rightArg.getBindingNames(), false);
			} else {
				result = new ParallelJoinCursor(this, result, join.getArg(i)); // NOPMD
				executor.execute((Runnable) result);
				collectedBindingNames.addAll(rightArg.getBindingNames());
			}
		}
		return result;
	}

	@Override
	public CloseableIteration evaluate(LeftJoin leftJoin,
			final BindingSet bindings) throws QueryEvaluationException {
		// Check whether optional join is "well designed" as defined in section
		// 4.2 of "Semantics and Complexity of SPARQL", 2006, Jorge Pérez et al.
		Set boundVars = bindings.getBindingNames();
		Set leftVars = leftJoin.getLeftArg().getBindingNames();
		Set optionalVars = leftJoin.getRightArg().getBindingNames();

		final Set problemVars = new HashSet<>(boundVars);
		problemVars.retainAll(optionalVars);
		problemVars.removeAll(leftVars);

		CloseableIteration result;
		if (problemVars.isEmpty()) {
			// left join is "well designed"
			result = new ParallelLeftJoinCursor(this, leftJoin, bindings);
			executor.execute((Runnable) result);
		} else {
			result = new BadlyDesignedLeftJoinIterator(this, leftJoin, bindings, problemVars);
		}
		return result;
	}

	@Override
	@SuppressWarnings("unchecked")
	public CloseableIteration evaluate(Union union, BindingSet bindings)
			throws QueryEvaluationException {
		CloseableIteration[] iters = new CloseableIteration[2];
		iters[0] = evaluate(union.getLeftArg(), bindings);
		iters[1] = evaluate(union.getRightArg(), bindings);
		return new UnionIteration<>(iters);
	}

	private CloseableIteration evaluate(OwnedTupleExpr expr, BindingSet bindings)
			throws QueryEvaluationException {
		CloseableIteration result = expr.evaluate(dataset, bindings);
		if (result == null) {
			TripleSource source = new org.eclipse.rdf4j.repository.evaluation.RepositoryTripleSource(expr.getOwner());
			EvaluationStrategy eval = new FederationStrategy(executor, source, dataset, serviceResolver);
			result = eval.evaluate(expr.getArg(), bindings);
		}
		return result;
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy