blob: b13398e35397d896ccfda409ae8a636163844032 [file] [log] [blame]
package org.apache.rya.rdftriplestore.inference;
/*
* 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.Set;
import java.util.UUID;
import org.apache.rya.api.RdfCloudTripleStoreConfiguration;
import org.apache.rya.api.utils.NullableStatementImpl;
import org.apache.rya.rdftriplestore.utils.FixedStatementPattern;
import org.eclipse.rdf4j.model.IRI;
import org.eclipse.rdf4j.model.vocabulary.RDF;
import org.eclipse.rdf4j.model.vocabulary.RDFS;
import org.eclipse.rdf4j.query.algebra.StatementPattern;
import org.eclipse.rdf4j.query.algebra.TupleExpr;
import org.eclipse.rdf4j.query.algebra.Var;
/**
* Expands the query tree to account for any relevant domain and range information known to the
* {@link InferenceEngine}.
*
* Given a triple <:s :p :o>, if :p has an rdfs:domain of :D and rdfs:range of :R, the semantics of
* domain and range imply that :s has type :D and that :o has type :R.
*
* Only operates on {@link StatementPattern} nodes whose form is <?subject rdfs:type :DefinedClass>.
* If the class is the domain of any predicate, as reported by the {@link InferenceEngine}, a
* subtree is constructed to infer the type based on the domain. If the class is the range of any
* predicate, a subtree is similarly constructed to infer the type based on the range. If one or
* both apply, then the original node is replaced with the union of the new subtree(s) and the
* original statement pattern.
*
* If there are multiple ways to infer the type for one resource, the resulting query tree will
* match all of them and produce multiple solutions for that resource.
*/
public class DomainRangeVisitor extends AbstractInferVisitor {
/**
* Creates a new {@link DomainRangeVisitor}.
* @param conf The {@link RdfCloudTripleStoreConfiguration}.
* @param inferenceEngine The InferenceEngine containing the relevant ontology.
*/
public DomainRangeVisitor(RdfCloudTripleStoreConfiguration conf, InferenceEngine inferenceEngine) {
super(conf, inferenceEngine);
include = conf.isInferDomainRange();
}
/**
* Checks whether this statement pattern might be inferred using domain and/or range knowledge,
* and, if so, replaces the statement pattern with a union of itself and any possible
* derivations.
*/
@Override
protected void meetSP(StatementPattern node) throws Exception {
final Var subjVar = node.getSubjectVar();
final Var predVar = node.getPredicateVar();
final Var objVar = node.getObjectVar();
final Var contextVar = node.getContextVar();
// Only applies to statement patterns that query for members of a defined type.
if (predVar != null && RDF.TYPE.equals(predVar.getValue())
&& objVar != null && objVar.getValue() instanceof IRI) {
final IRI inferredType = (IRI) objVar.getValue();
// Preserve the original node so explicit type assertions are still matched:
TupleExpr currentNode = node.clone();
// If there are any properties with this type as domain, check for appropriate triples:
final Set<IRI> domainProperties = inferenceEngine.getPropertiesWithDomain(inferredType);
if (!domainProperties.isEmpty()) {
Var domainPredVar = new Var("p-" + UUID.randomUUID());
Var domainObjVar = new Var("o-" + UUID.randomUUID());
domainObjVar.setAnonymous(true);
Var domainVar = new Var(RDFS.DOMAIN.stringValue(), RDFS.DOMAIN);
StatementPattern domainSP = new DoNotExpandSP(subjVar, domainPredVar, domainObjVar, contextVar);
// Enumerate predicates having this type as domain
FixedStatementPattern domainFSP = new FixedStatementPattern(domainPredVar, domainVar, objVar);
for (IRI property : domainProperties) {
domainFSP.statements.add(new NullableStatementImpl(property, RDFS.DOMAIN, inferredType));
}
// For each such predicate, any triple <subjVar predicate _:any> implies the type
currentNode = new InferUnion(currentNode, new InferJoin(domainFSP, domainSP));
}
// If there are any properties with this type as range, check for appropriate triples:
final Set<IRI> rangeProperties = inferenceEngine.getPropertiesWithRange(inferredType);
if (!rangeProperties.isEmpty()) {
Var rangePredVar = new Var("p-" + UUID.randomUUID());
Var rangeSubjVar = new Var("s-" + UUID.randomUUID());
rangeSubjVar.setAnonymous(true);
Var rangeVar = new Var(RDFS.RANGE.stringValue(), RDFS.RANGE);
StatementPattern rangeSP = new DoNotExpandSP(rangeSubjVar, rangePredVar, subjVar, contextVar);
// Enumerate predicates having this type as range
FixedStatementPattern rangeFSP = new FixedStatementPattern(rangePredVar, rangeVar, objVar);
for (IRI property : rangeProperties) {
rangeFSP.statements.add(new NullableStatementImpl(property, RDFS.RANGE, inferredType));
}
// For each such predicate, any triple <_:any predicate subjVar> implies the type
currentNode = new InferUnion(currentNode, new InferJoin(rangeFSP, rangeSP));
}
node.replaceWith(currentNode);
}
}
}