Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
#1553: remove NativeStore extensions and replace with strategy
The NativeStoreExt was used to evaluate pre-compiled TupleExpr without
applying any optimizer.

With the latest API changes to EvaluationStrategy we can solve the same
in the strategy.

Signed-off-by: Andreas Schwarte <aschwarte10@gmail.com>
  • Loading branch information
aschwarte10 committed Oct 1, 2019
1 parent b22ce54 commit 5346f78
Show file tree
Hide file tree
Showing 8 changed files with 226 additions and 316 deletions.
@@ -0,0 +1,43 @@
/*******************************************************************************
* Copyright (c) 2019 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.
*******************************************************************************/
package org.eclipse.rdf4j.federated.algebra;

import org.eclipse.rdf4j.federated.endpoint.provider.SailSourceEvaluationStrategyFactory;
import org.eclipse.rdf4j.federated.evaluation.SailTripleSource;
import org.eclipse.rdf4j.query.algebra.QueryRoot;
import org.eclipse.rdf4j.query.algebra.TupleExpr;

/**
* Node representing a precompiled query.
*
* @author Andreas Schwarte
* @see SailSourceEvaluationStrategyFactory
* @see SailTripleSource
*/
public class PrecompiledQueryNode extends QueryRoot {

private static final long serialVersionUID = -5382415823483370751L;

private TupleExpr query;

public PrecompiledQueryNode(TupleExpr query) {
super(query);
this.query = query;
}

public TupleExpr getQuery() {
return query;
}

@Override
public PrecompiledQueryNode clone() {
PrecompiledQueryNode clone = (PrecompiledQueryNode) super.clone();
clone.query = this.query;
return clone;
}
}
Expand Up @@ -15,16 +15,16 @@
import org.eclipse.rdf4j.federated.exception.FedXException;
import org.eclipse.rdf4j.federated.exception.FedXRuntimeException;
import org.eclipse.rdf4j.federated.util.FileUtil;
import org.eclipse.rdf4j.query.algebra.evaluation.EvaluationStrategyFactory;
import org.eclipse.rdf4j.repository.RepositoryException;
import org.eclipse.rdf4j.repository.sail.SailRepository;
import org.eclipse.rdf4j.sail.nativerdf.NativeStore;
import org.eclipse.rdf4j.sail.nativerdf.NativeStoreExt;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* Provider for an Endpoint that uses a RDF4J {@link NativeStore} as underlying repository. For optimization purposes
* the NativeStore is wrapped within a {@link NativeStoreExt} to allow for evaluation of prepared queries without prior
* the {@link SailSourceEvaluationStrategyFactory} is used to allow for evaluation of prepared queries without prior
* optimization. Note that NativeStores are always classified as 'Local'.
*
* <p>
Expand Down Expand Up @@ -63,7 +63,11 @@ public Endpoint loadEndpoint(NativeRepositoryInformation repoInfo) throws FedXEx
}

try {
NativeStore ns = new NativeStoreExt(store);
NativeStore ns = new NativeStore(store);
EvaluationStrategyFactory factory = new SailSourceEvaluationStrategyFactory(
ns.getEvaluationStrategyFactory());
ns.setEvaluationStrategyFactory(factory);

SailRepository repo = new SailRepository(ns);

try {
Expand Down
@@ -0,0 +1,150 @@
/*******************************************************************************
* Copyright (c) 2019 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.
*******************************************************************************/
package org.eclipse.rdf4j.federated.endpoint.provider;

import java.util.Optional;

import org.eclipse.rdf4j.common.iteration.CloseableIteration;
import org.eclipse.rdf4j.federated.algebra.PrecompiledQueryNode;
import org.eclipse.rdf4j.model.Value;
import org.eclipse.rdf4j.query.BindingSet;
import org.eclipse.rdf4j.query.Dataset;
import org.eclipse.rdf4j.query.QueryEvaluationException;
import org.eclipse.rdf4j.query.algebra.Service;
import org.eclipse.rdf4j.query.algebra.TupleExpr;
import org.eclipse.rdf4j.query.algebra.ValueExpr;
import org.eclipse.rdf4j.query.algebra.evaluation.EvaluationStrategy;
import org.eclipse.rdf4j.query.algebra.evaluation.EvaluationStrategyFactory;
import org.eclipse.rdf4j.query.algebra.evaluation.QueryOptimizerPipeline;
import org.eclipse.rdf4j.query.algebra.evaluation.TripleSource;
import org.eclipse.rdf4j.query.algebra.evaluation.ValueExprEvaluationException;
import org.eclipse.rdf4j.query.algebra.evaluation.federation.FederatedService;
import org.eclipse.rdf4j.query.algebra.evaluation.impl.BindingAssigner;
import org.eclipse.rdf4j.query.algebra.evaluation.impl.EvaluationStatistics;

/**
* An {@link EvaluationStrategyFactory} which allows the evaluation of {@link PrecompiledQueryNode} without prior
* optimization.
* <p>
* All other types of {@link TupleExpr} are optimized and evaluated through the configured delegate strategy, i.e.
* typically the one provided by the sail itself.
* </p>
*
* @author Andreas Schwarte
* @see NativeStoreProvider
*/
public class SailSourceEvaluationStrategyFactory implements EvaluationStrategyFactory {

private final EvaluationStrategyFactory delegate;

public SailSourceEvaluationStrategyFactory(EvaluationStrategyFactory delegate) {
super();
this.delegate = delegate;
}

@Override
public void setQuerySolutionCacheThreshold(long threshold) {
delegate.setQuerySolutionCacheThreshold(threshold);
}

@Override
public long getQuerySolutionCacheThreshold() {
return delegate.getQuerySolutionCacheThreshold();
}

@Override
public void setOptimizerPipeline(QueryOptimizerPipeline pipeline) {
delegate.setOptimizerPipeline(pipeline);
}

@Override
public Optional<QueryOptimizerPipeline> getOptimizerPipeline() {
return delegate.getOptimizerPipeline();
}

@Override
public EvaluationStrategy createEvaluationStrategy(Dataset dataset, TripleSource tripleSource,
EvaluationStatistics evaluationStatistics) {
EvaluationStrategy delegateStrategy = delegate.createEvaluationStrategy(dataset, tripleSource,
evaluationStatistics);
return new SailSourceEvaluationStrategy(delegateStrategy, dataset);
}

/**
* {@link EvaluationStrategy} that can handle {@link PrecompiledQueryNode} without prior optimization. All other
* {@link TupleExpr} are handled in the respective delegate.
*
* @author Andreas Schwarte
*
*/
private static class SailSourceEvaluationStrategy implements EvaluationStrategy {

private final EvaluationStrategy delegate;
private final Dataset dataset;

public SailSourceEvaluationStrategy(EvaluationStrategy delegate, Dataset dataset) {
super();
this.delegate = delegate;
this.dataset = dataset;
}

@Override
public FederatedService getService(String serviceUrl) throws QueryEvaluationException {
return delegate.getService(serviceUrl);
}

@Override
public void setOptimizerPipeline(QueryOptimizerPipeline pipeline) {
delegate.setOptimizerPipeline(pipeline);
}

@Override
public TupleExpr optimize(TupleExpr expr, EvaluationStatistics evaluationStatistics, BindingSet bindings) {

if (expr instanceof PrecompiledQueryNode) {
return optimizePreparedQuery((PrecompiledQueryNode) expr, bindings);
}
return delegate.optimize(expr, evaluationStatistics, bindings);
}

@Override
public CloseableIteration<BindingSet, QueryEvaluationException> evaluate(Service expr, String serviceUri,
CloseableIteration<BindingSet, QueryEvaluationException> bindings) throws QueryEvaluationException {
return delegate.evaluate(expr, serviceUri, bindings);
}

@Override
public CloseableIteration<BindingSet, QueryEvaluationException> evaluate(TupleExpr expr, BindingSet bindings)
throws QueryEvaluationException {
return delegate.evaluate(expr, bindings);
}

@Override
public Value evaluate(ValueExpr expr, BindingSet bindings)
throws ValueExprEvaluationException, QueryEvaluationException {
return delegate.evaluate(expr, bindings);
}

@Override
public boolean isTrue(ValueExpr expr, BindingSet bindings)
throws ValueExprEvaluationException, QueryEvaluationException {
return delegate.isTrue(expr, bindings);
}

protected TupleExpr optimizePreparedQuery(PrecompiledQueryNode preparedQuery, BindingSet bindings) {

TupleExpr actualQuery = preparedQuery.getQuery();

if (bindings != null) {
new BindingAssigner().optimize(actualQuery, dataset, bindings);
}

return actualQuery;
}
}
}
Expand Up @@ -13,6 +13,7 @@
import org.eclipse.rdf4j.common.iteration.Iterations;
import org.eclipse.rdf4j.federated.FederationManager;
import org.eclipse.rdf4j.federated.algebra.FilterValueExpr;
import org.eclipse.rdf4j.federated.algebra.PrecompiledQueryNode;
import org.eclipse.rdf4j.federated.endpoint.Endpoint;
import org.eclipse.rdf4j.federated.evaluation.iterator.FilteringInsertBindingsIteration;
import org.eclipse.rdf4j.federated.evaluation.iterator.FilteringIteration;
Expand All @@ -36,8 +37,6 @@
import org.eclipse.rdf4j.repository.RepositoryResult;
import org.eclipse.rdf4j.repository.sail.SailRepositoryConnection;
import org.eclipse.rdf4j.sail.SailConnection;
import org.eclipse.rdf4j.sail.SailException;
import org.eclipse.rdf4j.sail.nativerdf.NativeStoreConnectionExt;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand Down Expand Up @@ -181,27 +180,29 @@ public CloseableIteration<BindingSet, QueryEvaluationException> getStatements(
/*
* Implementation note:
*
* a hook is introduced for NativeStore instances such that an extended connection is used. The extended
* connection provides a method to evaluate prepared queries without prior (obsolete) optimization.
* a special strategy is registered for NativeStore instances. The specialized strategy allows to evaluate
* prepared queries without prior (obsolete) optimization.
*/
return withConnection((conn, resultHolder) -> {

CloseableIteration<BindingSet, QueryEvaluationException> res;
SailConnection sailConn = ((SailRepositoryConnection) conn).getSailConnection();

if (sailConn instanceof NativeStoreConnectionExt) {
NativeStoreConnectionExt _conn = (NativeStoreConnectionExt) sailConn;
res = (CloseableIteration<BindingSet, QueryEvaluationException>) _conn
.evaluatePrecompiled(preparedQuery);
} else {
try {
log.warn(
"Precompiled query optimization for native store could not be applied: use extended NativeStore initialization using NativeStoreConnectionExt");
res = (CloseableIteration<BindingSet, QueryEvaluationException>) sailConn.evaluate(preparedQuery,
null, EmptyBindingSet.getInstance(), true);
} catch (SailException e) {
throw new QueryEvaluationException(e);
}
try {

// optimization attempt: use precompiled query
PrecompiledQueryNode precompiledQueryNode = new PrecompiledQueryNode(preparedQuery);
res = (CloseableIteration<BindingSet, QueryEvaluationException>) sailConn.evaluate(precompiledQueryNode,
null, EmptyBindingSet.getInstance(), true);

} catch (Exception e) {
log.warn(
"Precompiled query optimization for native store could not be applied: " + e.getMessage());
log.debug("Details:", e);

// fallback: attempt the original tuple expression
res = (CloseableIteration<BindingSet, QueryEvaluationException>) sailConn.evaluate(preparedQuery,
null, EmptyBindingSet.getInstance(), true);
}

if (bindings.size() > 0) {
Expand Down

This file was deleted.

0 comments on commit 5346f78

Please sign in to comment.