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

fr.boreal.component_builder.ComponentBuilder Maven / Gradle / Ivy

There is a newer version: 1.6.2
Show newest version
package fr.boreal.component_builder;

import java.sql.SQLException;
import java.time.Duration;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import fr.boreal.backward_chaining.evaluators.QueryRewriter;
import fr.boreal.component_builder.api.IComponentBuilder;
import fr.boreal.component_builder.api.IOperationResult;
import fr.boreal.component_builder.api.algorithm.IAlgorithmParameters;
import fr.boreal.component_builder.api.scenario.IInputDataScenario;
import fr.boreal.component_builder.components.ChaseComponentBuilder;
import fr.boreal.component_builder.components.FactBaseLoaderFromFile;
import fr.boreal.component_builder.components.QueryAnsweringComponentBuilder;
import fr.boreal.component_builder.components.RewritingComponentBuilder;
import fr.boreal.component_builder.operations.FactBaseLoadingOperationResult;
import fr.boreal.component_builder.operations.OperationNotPerformed;
import fr.boreal.component_builder.operations.QueryBaseLoadingOperationResult;
import fr.boreal.component_builder.operations.RuleBaseLoadingOperationResult;
import fr.boreal.component_builder.operations.RuleCompilationOperationResult;
import fr.boreal.forward_chaining.chase.Chase;
import fr.boreal.io.dlgp.DlgpParser;
import fr.boreal.model.component.InteGraalKeywords;
import fr.boreal.model.component.InteGraalKeywords.Algorithms;
import fr.boreal.model.kb.api.FactBase;
import fr.boreal.model.kb.api.RuleBase;
import fr.boreal.model.kb.impl.RuleBaseImpl;
import fr.boreal.model.query.api.Query;
import fr.boreal.model.rule.api.FORule;
import fr.boreal.model.ruleCompilation.HierarchicalRuleCompilation;
import fr.boreal.model.ruleCompilation.NoRuleCompilation;
import fr.boreal.model.ruleCompilation.api.RuleCompilation;
import fr.boreal.model.ruleCompilation.api.RuleCompilationResult;
import fr.boreal.model.ruleCompilation.id.IDRuleCompilation;
import fr.boreal.query_evaluation.component.CountingQueryEvaluator;
import fr.boreal.query_evaluation.component.QueryEvaluationInput;
import fr.boreal.query_evaluation.component.QueryEvaluationOutput;
import fr.boreal.query_evaluation.component.QueryEvaluator;
import fr.boreal.storage.external.rdbms.RDBMSStore;
import fr.lirmm.boreal.util.evaluator.MultiEvaluator;
import fr.lirmm.boreal.util.externalHaltingConditions.ExternalAlgorithmHaltingConditions;

/**
 * 
 * A component builder is able to return an InteGraal object performing a main
 * task, such as chasing, rewriting, evaluating queries, compiling rules.
 * 
 */

public class ComponentBuilder implements IComponentBuilder {

	private static final Logger LOG = LoggerFactory.getLogger(ComponentBuilder.class);

	private final IInputDataScenario kbscenario;
	private final IAlgorithmParameters integraalAlgorithmParameters;

	private Optional factbase;
	private Optional> ruleset;
	private Optional> querybase;
	private Optional> queryEvaluator;

	private Optional chaseAlgorithm;
	private Optional rewriter;
	private Optional compilResult;

	private RuleCompilation compilation; // assumed to be always set

	///////////////////////////////
	///////////////////////////////
	///////////////////////////////
	///////////////////////////////
	/// CONSTURCTOR
	///////////////////////////////
	///////////////////////////////
	///////////////////////////////
	///////////////////////////////

	/**
	 * Constructs a component builder from the specified input scenario and
	 * algorithm parameters.
	 *
	 * @param inputScenario       the knowledge base scenario, not null.
	 * @param algorithmParameters the algorithm parameters for the InteGraal
	 *                            component, not null. base files specified by the
	 *                            by the kbscenario.
	 */

	public ComponentBuilder(IInputDataScenario inputScenario, IAlgorithmParameters algorithmParameters) {

		this.kbscenario = inputScenario;
		this.integraalAlgorithmParameters = algorithmParameters;

		this.factbase = Optional.empty();
		this.querybase = Optional.empty();
		this.ruleset = Optional.empty();

		this.compilResult = Optional.empty();

		this.queryEvaluator = Optional.empty();
		this.chaseAlgorithm = Optional.empty();
		this.rewriter = Optional.empty();

	}

	///////////////////////////////
	///////////////////////////////
	///////////////////////////////
	///////////////////////////////
	/// PUBLIC METHODS
	///////////////////////////////
	///////////////////////////////
	///////////////////////////////
	///////////////////////////////

	/**
	 * 
	 * Returns the factbase object used by the builder.
	 * 
	 */
	public FactBase getFactbase() {
		checkExists(factbase);
		return factbase.get();
	}

	/**
	 * 
	 * Returns a new rulebase containing all rules used by the builder.
	 * 
	 */

	public RuleBase getRulebase() {
		checkExists(ruleset);
		return new RuleBaseImpl(ruleset.get());
	}

	/**
	 * 
	 * Returns the query set object used by the builder.
	 * 
	 */

	public Collection getQueries() {
		checkExists(querybase);
		return querybase.get();
	}

	/**
	 * 
	 * Returns the rule compilation result used by the builder.
	 * 
	 */

	public RuleCompilationResult getRuleCompilationResult() {
		checkExists(compilResult);
		return compilResult.get();
	}

	/**
	 * Returns chase algorithm based on the provided configuration.
	 * 
	 * @return the prepared instance of the Chase algorithm.
	 */

	public Chase buildOrGetChase() {
		checkSaturationService();

		if (chaseAlgorithm.isPresent()) {
			return chaseAlgorithm.get();
		}

		checkNecessaryElementsForComponent(List.of(factbase, ruleset),
				InteGraalKeywords.Algorithms.KB_CHASE);

		Chase customizedChase = ChaseComponentBuilder.prepareAndGetChaseFrom(getFactbase(), getRulebase(),
				integraalAlgorithmParameters);

		this.chaseAlgorithm = Optional.ofNullable(customizedChase);

		return customizedChase;

	}

	/**
	 * 
	 * @return a rewriting algorithm based on the current configuration
	 */

	public QueryRewriter buildOrGetRewriter() {

		checkRewritingService();

		if (rewriter.isPresent()) {
			return rewriter.get();
		}

		checkNecessaryElementsForComponent(List.of(querybase, ruleset),
				InteGraalKeywords.Algorithms.OMQ_REWRITING);

		QueryRewriter customizedRewriter = RewritingComponentBuilder.prepareAndGetRewriterFrom(getQueries(),
				getRulebase(), getCompilation(), getExternalHaltingConditions());

		this.rewriter = Optional.of(customizedRewriter);

		return customizedRewriter;

	}

	private ExternalAlgorithmHaltingConditions getExternalHaltingConditions() {
		return this.integraalAlgorithmParameters.getExternalHaltingConditions();
	}

	private RuleCompilation getCompilation() {
		return this.compilation;
	}

	/**
	 * 
	 * 
	 * @return a query evaluator based on the current configuration
	 */
	public QueryEvaluator buildOrGetQueryAnsweringAlgorithm() {

		checkQueryAnsweringService();

		if (queryEvaluator.isPresent()) {
			return (QueryEvaluator) queryEvaluator.get();
		}

		checkNecessaryElementsForComponent(List.of(querybase, factbase),
				InteGraalKeywords.Algorithms.OMQ_REWRITING);

		QueryEvaluator customizedEvaluator = QueryAnsweringComponentBuilder
				.prepareAndGetQueryAnsweringFrom(getQueries(), getFactbase(), getExternalHaltingConditions());

		this.queryEvaluator = Optional.of(customizedEvaluator);

		return customizedEvaluator;

	}

	/**
	 * 
	 * 
	 * @return a query evaluator based on the current configuration
	 */
	public CountingQueryEvaluator buildOrGetCountingQueryAnsweringAlgorithm() {

		checkQueryAnsweringService();

		if (queryEvaluator.isPresent()) {
			return (CountingQueryEvaluator) queryEvaluator.get();
		}

		checkNecessaryElementsForComponent(List.of(querybase, factbase),
				InteGraalKeywords.Algorithms.OMQ_REWRITING);

		CountingQueryEvaluator customizedEvaluator = QueryAnsweringComponentBuilder
				.prepareAndGetCountingQueryAnsweringFrom(getQueries(), getFactbase(), getExternalHaltingConditions());

		this.queryEvaluator = Optional.of(customizedEvaluator);

		return customizedEvaluator;

	}

	/**
	 * 
	 * Loads the data into the factbase.
	 * @return metadata describing the operation result
	 *
	 */
	public IOperationResult trySetFactBase() {

		// note the abuse of switch notation
		this.factbase = switch (factbase) {

		case Optional o when kbscenario.getFactBase().isPresent() -> kbscenario.getFactBase();

		case Optional o when kbscenario.getFactbasePaths().isPresent() ->
			Optional.of(FactBaseLoaderFromFile.getFactbaseFor(kbscenario, integraalAlgorithmParameters));

		case Optional o when kbscenario.getMappingbasePaths().isPresent() ->
			Optional.of(FactBaseLoaderFromFile.getFederatedFactbaseFor(kbscenario, integraalAlgorithmParameters));

		default -> {
			LOG.warn("Asked to load factbase but no factbase input has been set.");
			yield Optional.empty();
		}

		};

		if (this.factbase.isPresent()) {

			return new FactBaseLoadingOperationResult(this.factbase.get());

		} else {

			return new OperationNotPerformed(InteGraalKeywords.MonitoringOperations.LOAD_FACTBASE);
		}
	}

	@Override
	public void init() {

		trySetFactBase();

		trySetRuleBase();

		trySetQueryBase();

		tryCompileRuleset();

	}

	/**
	 * sets the rule base
	 */
	public IOperationResult trySetRuleBase() {

		// note the abuse of switch notation
		this.ruleset = switch (ruleset) {

		case Optional> r when kbscenario.getRuleBase().isPresent() ->
			// we create a new collection holding the rules in the provided rule base
			Optional.of(new HashSet<>(kbscenario.getRuleBase().get().getRules()));

		case Optional> r when kbscenario.getRulebasePath().isPresent() ->
			Optional.of(DlgpParser.parseFiles(kbscenario.getRulebasePath().get()).rules());

		default -> Optional.empty();

		};

		if (this.ruleset.isPresent()) {
			return new RuleBaseLoadingOperationResult(new RuleBaseImpl(this.ruleset.get()));
		} else {
			return new OperationNotPerformed(InteGraalKeywords.MonitoringOperations.LOAD_RULEBASE);
		}

	}

	/**
	 * sets the query base
	 */
	public IOperationResult trySetQueryBase() {

		// note the abuse of switch notation
		this.querybase = switch (querybase) {

		case Optional> q when kbscenario.getQueryBase().isPresent() ->
			Optional.of(kbscenario.getQueryBase().get());

		case Optional> q when kbscenario.getQuerybasePaths().isPresent() ->
			Optional.of(DlgpParser.parseFiles(kbscenario.getQuerybasePaths().get()).queries());

		default -> Optional.empty();
		};

		if (this.querybase.isPresent()) {
			return new QueryBaseLoadingOperationResult(this.querybase.get());
		} else {
			return new OperationNotPerformed(InteGraalKeywords.MonitoringOperations.LOAD_QUERY_WORKLOAD);
		}
	}

	/**
	 * (if required) compiles the rules
	 */
	public IOperationResult tryCompileRuleset() {

		if (ruleset.isEmpty() || integraalAlgorithmParameters.getCompilation().isEmpty()) {
			// sanity check not passed
			this.compilation = NoRuleCompilation.instance();
			this.compilResult = Optional.empty();
			return new OperationNotPerformed(InteGraalKeywords.Algorithms.RULE_COMPILATION);

		}

		this.compilation = switch (integraalAlgorithmParameters.getCompilation().get()) {

		case HIERARCHICAL_COMPILATION -> new HierarchicalRuleCompilation();
		case ID_COMPILATION -> new IDRuleCompilation();
		default -> NoRuleCompilation.instance();
		};

		this.compilResult = Optional.ofNullable(compilation.compileAndGet(getRulebase()));

		if (this.compilResult.isPresent()) {
			return new RuleCompilationOperationResult(this.compilResult.get());
		} else {
			return new OperationNotPerformed(InteGraalKeywords.Algorithms.RULE_COMPILATION);
		}
	}


	/**
	 * Checks that all necessary elements are present for component creation.
	 *
	 * @param list             a list of optional elements to check.
	 * @param servicePrintOnly the name of the service being checked (optional).
	 * @throws IllegalArgumentException if any required element is missing.
	 */
	static void checkNecessaryElementsForComponent(List> list, Algorithms servicePrintOnly) {
		if (list.stream().anyMatch(Optional::isEmpty)) {
			throw new IllegalArgumentException("One of the elements for "
					+ ((servicePrintOnly != null) ? servicePrintOnly : "unspecified-service") + " is undefined.");
		}
	}

	///////////////////////////////
	///////////////////////////////
	///////////////////////////////
	///////////////////////////////
	/// PRIVATE METHODS
	///////////////////////////////
	///////////////////////////////
	///////////////////////////////
	///////////////////////////////

	private void checkSaturationService() {
		checkService(InteGraalKeywords.Algorithms.KB_CHASE, InteGraalKeywords.Algorithms.OMQA_CHASE,
				InteGraalKeywords.Algorithms.QUERY_ANSWERING_VIA_HYBRID_STRATEGY);
	}

	private void checkRewritingService() {
		checkService(InteGraalKeywords.Algorithms.OMQ_REWRITING, InteGraalKeywords.Algorithms.OMQA_REW,
				InteGraalKeywords.Algorithms.QUERY_ANSWERING_VIA_HYBRID_STRATEGY);
	}

	private void checkQueryAnsweringService() {
		checkService(InteGraalKeywords.Algorithms.QUERY_ANSWERING);
	}

	private void checkExists(Optional singleObject) {
		checkNecessaryElementsForComponent(List.of(singleObject), null);
	}

	/**
	 * 
	 * Checks if the algorithm to run is compatible with the service.
	 * 
	 * @param serviceList
	 */

	private void checkService(Algorithms... serviceList) {
		boolean supportedService = false;
		for (Algorithms service : serviceList) {
			if (integraalAlgorithmParameters.getAlgorithm().equals(service)) {
				supportedService = true;
			}
		}

		if (!supportedService) {
			throw new IllegalStateException("Unsupported service for " + integraalAlgorithmParameters.getAlgorithm());
		}
	}

	private Duration getTimeout() {
		return integraalAlgorithmParameters.getTimeout().isPresent() ? integraalAlgorithmParameters.getTimeout().get()
				: null;
	}

	public void close() {
		closeDatabaseConnectionsIfAny();
	}

	private void closeDatabaseConnectionsIfAny() {
		if (this.factbase.isEmpty()) {
			return;
		}

        if (this.factbase.get() instanceof RDBMSStore s) {
            try {
                s.getDriver().getConnection().close();
            } catch (SQLException e) {
                LOG.error("error while closing the database connection");
				throw new RuntimeException(
						String.format(
								"[%s::closeDatabaseConnectionsIfAny] error while closing the database connection.",
								this.getClass()));
            }
        }
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy