org.mindswap.pellet.jena.ModelExtractor Maven / Gradle / Ivy
The newest version!
// Portions Copyright (c) 2006 - 2008, Clark & Parsia, LLC.
// Clark & Parsia, LLC parts of this source code are available under the terms of the Affero General Public License v3.
//
// Please see LICENSE.txt for full license terms, including the availability of proprietary exceptions.
// Questions, comments, or requests for clarification: [email protected]
package org.mindswap.pellet.jena;
import static org.mindswap.pellet.jena.JenaUtils.makeGraphNode;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.mindswap.pellet.KnowledgeBase;
import org.mindswap.pellet.Role;
import org.mindswap.pellet.jena.vocabulary.OWL2;
import org.mindswap.pellet.utils.iterator.IteratorUtils;
import aterm.ATermAppl;
import com.hp.hpl.jena.graph.Node;
import com.hp.hpl.jena.graph.Triple;
import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.rdf.model.ModelFactory;
import com.hp.hpl.jena.util.iterator.Filter;
import com.hp.hpl.jena.vocabulary.OWL;
import com.hp.hpl.jena.vocabulary.RDF;
import com.hp.hpl.jena.vocabulary.RDFS;
import com.hp.hpl.jena.vocabulary.ReasonerVocabulary;
/**
* Extract a Jena model that contains the information Pellet inferred. Models
* can be generated about classes, properties or individuals. Note that
* individual models do not contain any information about property assertions,
* it just contains type assertions about individuals.
*
* @author Evren Sirin
*
*/
public class ModelExtractor {
/**
* Enumeration of types of statements that can be retrieved
*/
public enum StatementType {
/**
* for individuals, rdf:type statements (includes super-classes)
*/
ALL_INSTANCE,
/**
* for classes, rdfs:subClassOf statements (includes all super-classes)
*/
ALL_SUBCLASS,
/**
* for properties, rdfs:subPropertyOf statements (includes all
* super-properties)
*/
ALL_SUBPROPERTY,
/**
* for classes, owl:complementOf statements
*/
COMPLEMENT_CLASS,
/**
* for individuals, data property value statements
*/
DATA_PROPERTY_VALUE,
/**
* for individuals, owl:differentFrom statements
*/
DIFFERENT_FROM,
/**
* for individuals, rdf:type statements (only the most specific classes)
*/
DIRECT_INSTANCE,
/**
* for classes, rdfs:subClassOf statements (includes only direct
* super-classes)
*/
DIRECT_SUBCLASS,
/**
* for properties, rdfs:subPropertyOf statements (includes only direct
* super-properties)
*/
DIRECT_SUBPROPERTY,
/**
* for classes, owl:disjointWith statements
*/
DISJOINT_CLASS,
/**
* for classes, owl:propertyDisjointWith statements
*/
DISJOINT_PROPERTY,
/**
* for classes, owl:equivalentClass statements
*/
EQUIVALENT_CLASS,
/**
* for properties, owl:equivalentProperty statements
*/
EQUIVALENT_PROPERTY,
/**
* for properties, owl:inverseOf statements
*/
INVERSE_PROPERTY,
/**
* for individuals, jena reasoner vocabulary direct rdf:type statements
*/
JENA_DIRECT_INSTANCE,
/**
* for classes, jena reasoner vocabulary direct rdfs:subClassOf
* statements
*/
JENA_DIRECT_SUBCLASS,
/**
* for properties, jena reasoner vocabulary direct rdfs:subPropertyOf
* statements
*/
JENA_DIRECT_SUBPROPERTY,
/**
* for individuals, object property value statements
*/
OBJECT_PROPERTY_VALUE,
/**
* for individuals, owl:sameAs statements
*/
SAME_AS;
/**
* All statements about classes
*/
public static final EnumSet ALL_CLASS_STATEMENTS;
/**
* All statements about individuals
*/
public static final EnumSet ALL_INDIVIDUAL_STATEMENTS;
/**
* All statements about properties
*/
public static final EnumSet ALL_PROPERTY_STATEMENTS;
/**
* All statements (without Jena predicates for direct relations)
*/
public static final EnumSet ALL_STATEMENTS;
/**
* All statements (including Jena predicates for direct relations)
*/
public static final EnumSet ALL_STATEMENTS_INCLUDING_JENA;
/**
* All property values (both object and data)
*/
public static final EnumSet PROPERTY_VALUE;
/**
* Default statements
*/
public static final EnumSet DEFAULT_STATEMENTS;
static {
ALL_CLASS_STATEMENTS = EnumSet.of( ALL_SUBCLASS, COMPLEMENT_CLASS, DIRECT_SUBCLASS,
DISJOINT_CLASS, EQUIVALENT_CLASS );
ALL_INDIVIDUAL_STATEMENTS = EnumSet.of( ALL_INSTANCE, DATA_PROPERTY_VALUE,
DIFFERENT_FROM, DIRECT_INSTANCE, OBJECT_PROPERTY_VALUE, SAME_AS );
ALL_PROPERTY_STATEMENTS = EnumSet.of( ALL_SUBPROPERTY, DIRECT_SUBPROPERTY,
EQUIVALENT_PROPERTY, INVERSE_PROPERTY, DISJOINT_PROPERTY );
ALL_STATEMENTS = EnumSet.complementOf( EnumSet.of(
JENA_DIRECT_INSTANCE, JENA_DIRECT_SUBCLASS, JENA_DIRECT_SUBPROPERTY ) );
ALL_STATEMENTS_INCLUDING_JENA = EnumSet.allOf( StatementType.class );
DEFAULT_STATEMENTS = EnumSet.of( StatementType.DIRECT_SUBCLASS,
StatementType.EQUIVALENT_CLASS, StatementType.DIRECT_INSTANCE,
StatementType.OBJECT_PROPERTY_VALUE, StatementType.DATA_PROPERTY_VALUE,
StatementType.DIRECT_SUBPROPERTY, StatementType.EQUIVALENT_PROPERTY,
StatementType.INVERSE_PROPERTY );
PROPERTY_VALUE = EnumSet.of( StatementType.DATA_PROPERTY_VALUE,
StatementType.OBJECT_PROPERTY_VALUE );
}
}
/**
* A filter that does not accept anything.
*/
public static final Filter FILTER_NONE = new Filter() {
@Override
public boolean accept(Triple o) {
return false;
}
};
/**
* Associated KB
*/
private KnowledgeBase kb;
/**
* Filter that will be used to drop inferences
*/
private Filter filter = FILTER_NONE;
/**
* Controls the selected statements for methods where no selector is passed
* (initial setup intended to be backwards compatible)
*/
private EnumSet selector = StatementType.DEFAULT_STATEMENTS;
/**
* Initialize an empty extractor
*/
public ModelExtractor() {
}
/**
* Initialize the extractor with a Jena model that is backed by PelletInfGraph.
*
* @throws ClassCastException if the model.getGraph() does not return an instance of PelletInfGraph
*/
public ModelExtractor(Model model) throws ClassCastException {
this( (PelletInfGraph) model.getGraph() );
}
/**
* Initialize the extractor with a PelletInfGraph
*/
public ModelExtractor(PelletInfGraph graph) {
this( graph.getPreparedKB() );
}
/**
* Initialize the extractor with a reasoner
*/
public ModelExtractor(KnowledgeBase kb) {
setKB( kb );
}
/**
* Creates and adds the triple to the given list if the triple passes
* the filter.
*
* @param triples List to be added
* @param s subject of the triple
* @param p predicate of the triple
* @param o object of the triple
*/
private void addTriple(List triples, Node s, Node p, Node o) {
Triple triple = Triple.create( s, p, o );
if( !filter.accept( triple ) )
triples.add( triple );
}
public Model extractClassModel() {
return extractClassModel( ModelFactory.createDefaultModel() );
}
public Model extractClassModel(Model model) {
final boolean allSubs = selector.contains( StatementType.ALL_SUBCLASS );
final boolean jenaDirectSubs = selector.contains( StatementType.JENA_DIRECT_SUBCLASS );
final boolean subs = allSubs || jenaDirectSubs
|| selector.contains( StatementType.DIRECT_SUBCLASS );
final boolean equivs = selector.contains( StatementType.EQUIVALENT_CLASS );
final boolean disjs = selector.contains( StatementType.DISJOINT_CLASS );
final boolean comps = selector.contains( StatementType.COMPLEMENT_CLASS );
if( subs || equivs || disjs || comps )
kb.classify();
List triples = new ArrayList();
Set classes = kb.getAllClasses();
for( ATermAppl c : classes ) {
triples.clear();
Node s, p;
s = makeGraphNode( c );
addTriple( triples, s, RDF.type.asNode(), OWL.Class.asNode() );
if( subs ) {
p = RDFS.subClassOf.asNode();
if( allSubs ) {
Set eqs = kb.getAllEquivalentClasses( c );
for( ATermAppl eq : eqs ) {
Node o = makeGraphNode( eq );
addTriple( triples, s, p, o );
}
}
Set> supers = allSubs
? kb.getSuperClasses( c, false )
: kb.getSuperClasses( c, true );
Iterator i = IteratorUtils.flatten( supers.iterator() );
while( i.hasNext() ) {
Node o = makeGraphNode( i.next() );
addTriple( triples, s, p, o );
}
if( jenaDirectSubs ) {
p = ReasonerVocabulary.directSubClassOf.asNode();
Set> direct = allSubs
? kb.getSuperClasses( c, true )
: supers;
i = IteratorUtils.flatten( direct.iterator() );
while( i.hasNext() ) {
Node o = makeGraphNode( i.next() );
addTriple( triples, s, p, o );
}
}
}
if( equivs ) {
p = OWL.equivalentClass.asNode();
Set eqs = kb.getAllEquivalentClasses( c );
for( ATermAppl a : eqs ) {
Node o = makeGraphNode( a );
addTriple( triples, s, p, o );
}
}
if( disjs ) {
Set> disj = kb.getDisjointClasses( c );
if( !disj.isEmpty() ) {
p = OWL.disjointWith.asNode();
Iterator i = IteratorUtils.flatten( disj.iterator() );
while( i.hasNext() ) {
ATermAppl a = i.next();
if( classes.contains( a ) )
addTriple( triples, s, p, makeGraphNode( a ) );
}
}
}
if( comps ) {
Set comp = kb.getComplements( c );
if( !comp.isEmpty() ) {
p = OWL.complementOf.asNode();
for( ATermAppl a : comp ) {
if( classes.contains( a ) )
addTriple( triples, s, p, makeGraphNode( a ) );
}
}
}
model.getGraph().getBulkUpdateHandler().add( triples );
}
return model;
}
/**
* Extract statements about individuals
*/
public Model extractIndividualModel() {
return extractIndividualModel( ModelFactory.createDefaultModel() );
}
/**
* Extract statements about individuals
*/
public Model extractIndividualModel(Model model) {
/*
* Initialize booleans that reflect the selector parameter - this avoids
* doing set contains evaluations for each pass of the loop.
*/
final boolean allClasses = selector.contains( StatementType.ALL_INSTANCE );
final boolean jenaDirectClasses = selector.contains( StatementType.JENA_DIRECT_INSTANCE );
final boolean classes = allClasses || jenaDirectClasses
|| selector.contains( StatementType.DIRECT_INSTANCE );
final boolean sames = selector.contains( StatementType.SAME_AS );
final boolean diffs = selector.contains( StatementType.DIFFERENT_FROM );
final boolean objValues = selector.contains( StatementType.OBJECT_PROPERTY_VALUE );
final boolean dataValues = selector.contains( StatementType.DATA_PROPERTY_VALUE );
if( classes )
kb.realize();
List triples = new ArrayList();
for( ATermAppl ind : kb.getIndividuals() ) {
triples.clear();
Node s, p;
s = makeGraphNode( ind );
if( classes ) {
p = RDF.type.asNode();
Set> types = kb.getTypes( ind, !allClasses );
Iterator i = IteratorUtils.flatten( types.iterator() );
while( i.hasNext() ) {
Node o = makeGraphNode( i.next() );
addTriple( triples, s, p, o );
}
if( jenaDirectClasses ) {
p = ReasonerVocabulary.directRDFType.asNode();
Set> directTypes = allClasses
? kb.getTypes( ind, true )
: types;
i = IteratorUtils.flatten( directTypes.iterator() );
while( i.hasNext() ) {
Node o = makeGraphNode( i.next() );
addTriple( triples, s, p, o );
}
}
}
if( sames ) {
p = OWL.sameAs.asNode();
addTriple( triples, s, p, s );
for( ATermAppl a : kb.getSames( ind ) ) {
addTriple( triples, s, p, makeGraphNode( a ) );
}
}
if( diffs ) {
p = OWL.differentFrom.asNode();
for( ATermAppl a : kb.getDifferents( ind ) ) {
addTriple( triples, s, p, makeGraphNode( a ) );
}
}
if( dataValues || objValues ) {
for( Role role : kb.getRBox().getRoles() ) {
if( role.isAnon() )
continue;
List values;
ATermAppl name = role.getName();
if( role.isDatatypeRole() ) {
if( dataValues )
values = kb.getDataPropertyValues( name, ind );
else
continue;
}
else if( role.isObjectRole() ) {
if( objValues )
values = kb.getObjectPropertyValues( name, ind );
else
continue;
}
else
continue;
if( values.isEmpty() )
continue;
p = makeGraphNode( name );
for( ATermAppl value : values ) {
addTriple( triples, s, p, makeGraphNode( value ) );
}
}
}
model.getGraph().getBulkUpdateHandler().add( triples );
}
return model;
}
public Model extractModel() {
return extractModel( ModelFactory.createDefaultModel() );
}
public Model extractModel(Model model) {
extractClassModel( model );
extractPropertyModel( model );
extractIndividualModel( model );
return model;
}
public Model extractPropertyModel() {
return extractPropertyModel( ModelFactory.createDefaultModel() );
}
public Model extractPropertyModel(Model model) {
final boolean allSubs = selector.contains( StatementType.ALL_SUBPROPERTY );
final boolean jenaDirectSubs = selector.contains( StatementType.JENA_DIRECT_SUBPROPERTY );
final boolean subs = allSubs || jenaDirectSubs
|| selector.contains( StatementType.DIRECT_SUBPROPERTY );
final boolean equivs = selector.contains( StatementType.EQUIVALENT_PROPERTY );
final boolean invs = selector.contains( StatementType.INVERSE_PROPERTY );
final boolean disjs = selector.contains( StatementType.DISJOINT_PROPERTY );
kb.prepare();
List triples = new ArrayList();
for( Role role : kb.getRBox().getRoles() ) {
triples.clear();
if( role.isAnon() )
continue;
ATermAppl name = role.getName();
Node s, p;
s = makeGraphNode( name );
p = RDF.type.asNode();
if( role.isDatatypeRole() )
addTriple( triples, s, p, OWL.DatatypeProperty.asNode() );
else if( role.isObjectRole() )
addTriple( triples, s, p, OWL.ObjectProperty.asNode() );
else
continue;
if( role.isFunctional() )
addTriple( triples, s, p, OWL.FunctionalProperty.asNode() );
if( role.isInverseFunctional() )
addTriple( triples, s, p, OWL.InverseFunctionalProperty.asNode() );
if( role.isTransitive() )
addTriple( triples, s, p, OWL.TransitiveProperty.asNode() );
if( role.isSymmetric() )
addTriple( triples, s, p, OWL.SymmetricProperty.asNode() );
if( equivs ) {
p = OWL.equivalentProperty.asNode();
for( ATermAppl eq : kb.getAllEquivalentProperties( name ) ) {
Node o = makeGraphNode( eq );
addTriple( triples, s, p, o );
if( allSubs )
addTriple( triples, s, RDFS.subPropertyOf.asNode(), o );
}
}
if( invs ) {
Set inverses = kb.getInverses( name );
if( !inverses.isEmpty() ) {
p = OWL.inverseOf.asNode();
for( ATermAppl inverse : inverses ) {
addTriple( triples, s, p, makeGraphNode( inverse ) );
}
}
}
if( disjs ) {
Set> disjoints = kb.getDisjointProperties( name );
if( !disjoints.isEmpty() ) {
p = OWL2.propertyDisjointWith.asNode();
Iterator i = IteratorUtils.flatten( disjoints.iterator() );
while( i.hasNext() ) {
Node o = makeGraphNode( i.next() );
addTriple( triples, s, p, o );
}
}
}
if( subs ) {
p = RDFS.subPropertyOf.asNode();
if( allSubs ) {
Set eqs = kb.getAllEquivalentProperties( name );
for( ATermAppl eq : eqs ) {
Node o = makeGraphNode( eq );
addTriple( triples, s, p, o );
}
}
Set> supers = kb.getSuperProperties( name, !allSubs );
if( !supers.isEmpty() ) {
Iterator i = IteratorUtils.flatten( supers.iterator() );
while( i.hasNext() ) {
Node o = makeGraphNode( i.next() );
addTriple( triples, s, p, o );
}
if( jenaDirectSubs ) {
p = ReasonerVocabulary.directSubPropertyOf.asNode();
Set> direct = allSubs
? kb.getSuperProperties( name, true )
: supers;
i = IteratorUtils.flatten( direct.iterator() );
while( i.hasNext() ) {
Node o = makeGraphNode( i.next() );
addTriple( triples, s, p, o );
}
}
}
}
// FIXME: Add domain statements
// FIXME: Add range statements
model.getGraph().getBulkUpdateHandler().add( triples );
}
return model;
}
/**
* Get the selector
*/
public EnumSet getSelector() {
return selector;
}
/**
* Sets the selector
*/
public void setSelector(EnumSet selector) {
this.selector = selector;
}
/**
* @return Returns the reasoner.
*/
public KnowledgeBase getKB() {
return kb;
}
/**
* @param reasoner
* The reasoner to set.
*/
public void setKB(KnowledgeBase kb) {
this.kb = kb;
}
/**
* Get the filter used to filter out any unwanted inferences from the result.
*
* @return
*/
public Filter getFilter() {
return filter;
}
/**
* Sets the filter that will filter out any unwanted inferences from the result. The
* filter should process {@link Triple} objects and return true
for any
* triple that should not be included in the result. Use {@link #FILTER_NONE} to disable
* filtering.
*
* @param filter
*/
public void setFilter(Filter filter) {
if( filter == null )
throw new NullPointerException( "Filter cannot be null" );
this.filter = filter;
}
}