I have created an ontology containing two classes, the first one is named Father
and the second is a subclass named Son
. I would like to set the following conditions to the class father using Jena
Has only son.
Has some son.
Then I would do the same for class Son
:
has exactly some father.
My second issue is that I don't know how to associate the instance of class Son
to the class Father
using also Jena. I know it's possible to manipulate my classes using Protégé, but I want to explore Jena.
The things that you're trying to do are not very difficult in Jena, but it sounds like there is some confusion about OWL. Given two classes B and C, if B is subclass of C, it means that every is B is also a C. So while it's true that
(1) Father subClassOf Son
since every father is also someone else's son, it's not true that
(2) Son subClassOf Father
since not every son is also a father. The restrictions that you've described also don't make a lot of sense. A cardinality restriction can be used to assert that each of instance of a class is related to exactly (or at least, or at most) some number of instances of another class by some particular property. Thus, you would probably say that
(3) Son subClassOf (hasFather exactly 1 Father)
to assert that each instance of Son is related to exactly one instance of Father. You could also say that each Father must have at least at least one Child (and I'd use Child here, rather than Son, since a child could also be a Daughter) by
(4) Father subClassOf (hasChild some Child)
but if you're only modeling male persons, I guess you could say
(5) Father subClassOf (hasSon some Son)
or
(6) Father subClassOf (hasSon min 1 Son)
Let's create an OntModel that includes the classes Son and Father and the axioms (1), (3), and (5). Then we'll add an instance of Father, AbrahamLincoln, and an instance of Son, RobertToddLincoln, and the appropriate relationships between them:
(7) RobertToddLincoln hasFather AbrahamLincoln
(8) AbrahamLincoln hasSon RobertToddLincoln
Now, we'll actually run into one problem right away: quantified cardinality restrictions are a part of OWL2, but not of OWL1, and Jena doesn't support OWL2 yet. Fortunately, in this case we can work around this, but saying that Sons only have Fathers as fathers, and that Sons have exactly one father:
(3'a) Son subClassOf (hasFather only Father)
(3'b) Son subClassOf (hasFather exactly 1)
The code you end up with is:
import com.hp.hpl.jena.ontology.Individual;
import com.hp.hpl.jena.ontology.OntClass;
import com.hp.hpl.jena.ontology.OntModel;
import com.hp.hpl.jena.ontology.OntModelSpec;
import com.hp.hpl.jena.ontology.OntProperty;
import com.hp.hpl.jena.rdf.model.ModelFactory;
public class FatherSonOntology {
public static void main(String[] args) {
final String ns = "http://example.org/";
final OntModel model = ModelFactory.createOntologyModel( OntModelSpec.OWL_DL_MEM );
model.setNsPrefix( "ex", ns );
final OntClass son = model.createClass( ns+"Son" );
final OntClass father = model.createClass( ns+"Father" );
final OntProperty hasFather = model.createObjectProperty( ns+"hasFather" );
final OntProperty hasSon = model.createObjectProperty( ns+"hasSon" );
// (1) Father subClassOf Son
son.addSubClass( father );
// (3'a) Son subClassOf (hasFather only Father)
son.addSubClass( model.createAllValuesFromRestriction( null, hasFather, father ));
// (3'b) Son subClassOf (hasFather exactly 1)
son.addSubClass( model.createCardinalityRestriction( null, hasFather, 1 ));
// (5) Father subClassOf (hasSon min 1 Son)
father.addSubClass( model.createSomeValuesFromRestriction( null, hasSon, son ));
// You can create individuals of a given type using Individual#createIndividual,
// or with Model#createIndividual.
final Individual abe = father.createIndividual( ns+"AbrahamLincoln" );
final Individual rob = model.createIndividual( ns+"RobertToddLincoln", son );
// You can add properties to individuals using Individual#addProperty, or you can
// use the various Model#add methods to add statements to the model.
rob.addProperty( hasFather, abe ); // (7)
model.add( abe, hasSon, rob ); // (8)
model.write( System.out, "RDF/XML-ABBREV" );
}
}
which prints the ontology at the end (which you could save and open in Protégé to check that everything appears as expected):
<rdf:RDF
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:owl="http://www.w3.org/2002/07/owl#"
xmlns:ex="http://example.org/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema#"
xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#">
<owl:Class rdf:about="http://example.org/Father">
<rdfs:subClassOf>
<owl:Class rdf:about="http://example.org/Son"/>
</rdfs:subClassOf>
</owl:Class>
<owl:ObjectProperty rdf:about="http://example.org/hasSon"/>
<owl:ObjectProperty rdf:about="http://example.org/hasFather"/>
<owl:Restriction>
<rdfs:subClassOf rdf:resource="http://example.org/Son"/>
<owl:allValuesFrom rdf:resource="http://example.org/Father"/>
<owl:onProperty rdf:resource="http://example.org/hasFather"/>
</owl:Restriction>
<owl:Restriction>
<rdfs:subClassOf rdf:resource="http://example.org/Father"/>
<owl:someValuesFrom rdf:resource="http://example.org/Son"/>
<owl:onProperty rdf:resource="http://example.org/hasSon"/>
</owl:Restriction>
<owl:Restriction>
<rdfs:subClassOf rdf:resource="http://example.org/Son"/>
<owl:cardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#int"
>1</owl:cardinality>
<owl:onProperty rdf:resource="http://example.org/hasFather"/>
</owl:Restriction>
<ex:Son rdf:about="http://example.org/RobertToddLincoln">
<ex:hasFather>
<ex:Father rdf:about="http://example.org/AbrahamLincoln">
<ex:hasSon rdf:resource="http://example.org/RobertToddLincoln"/>
</ex:Father>
</ex:hasFather>
</ex:Son>
</rdf:RDF>