How to add qualified cardinality in JENA

2019-02-10 20:34发布

问题:

How can I add qualified cardinality restriction in Jena? I can not use createCardinalityQRestriction because the OntModelSpec is for the first version of OWL, not OWL2. In ModelFactory's createOntologyModel, is there a way to create an OWL2 ontology? I need a class expression like

JeVysledkom exactly 1 Kolik_Fazovy

I've tried using this code:

OntModel ontModel = ModelFactory.createOntologyModel();
OntClass ret = ontModel.createCardinalityQRestriction(null, ontProperty, cardinality,    ontClass2 );
ontClass.addSuperClass(ret);

but I get this exception:

com.hp.hpl.jena.ontology.ProfileException: Attempted to use language construct CARDINALITY_Q that is not supported in the current language profile: OWL Full

回答1:

I actually just ran into this while handling another question, Adding more complicated subclass axiom. Creating this in Jena is a little bit tricky because support for the qualified cardinality restrictions is an OWL2 feature, and Jena has limited support for OWL2:

Jena Ontology API

Note that, at present, the Jena ontology API has only limited support for OWL2's qualified cardinality restrictions (i.e. cardinalityQ, minCardinalityQ and maxCardinalityQ). Qualified cardinality restrictions are encapsulated in the interfaces CardinalityQRestriction, MinCardinalityQRestriction and CardinalityQRestriction. OntModel also provides methods for creating and accessing qualified cardinality restrictions. Since they are not part of the OWL 1.0 language definition, qualified cardinality restrictions are not supported in OWL ontologies. Qualified cardinality restrictions were added to the OWL 2 update. OWL2 support in Jena will be added in due course.

Additionally, the Javadoc for the OWL2 vocabulary class says:

OWL2 vocabulary. NOTE: Jena does not provide OWL2 inference or OntModel support. These constants are provided for the convenience of users who are doing OWL2 work with the current OWL1 support and desire a suitable set of names.

You might also see a response that I posted to the Jena mailing list about a similar question, Re: Owl maxCardinality restriction.

But you want to create one anyway? Then you're one of those “users who are doing OWL2 work with the current OWL1 support and desire a suitable set of names.” To find out how the OWL2 construction should be serialized in RDF, we need to take a look at OWL 2 Web Ontology Language Mapping to RDF Graphs (Second Edition), particularly section 2 Mapping from the Structural Specification to RDF Graphs, which tells us that the class expression

ObjectExactCardinality( n OPE CE )

is serialized as the following set of triples

_:x rdf:type owl:Restriction .
_:x owl:onProperty T(OPE) .
_:x owl:qualifiedCardinality "n"^^xsd:nonNegativeInteger .
_:x owl:onClass T(CE) .

where _:x is the resource that is the class. The non-qualified case, which Jena already handles, turns

ObjectExactCardinality( n OPE )

into

_:x rdf:type owl:Restriction .
_:x owl:onProperty T(OPE) .
_:x owl:cardinality "n"^^xsd:nonNegativeInteger .

If we had one of the latter, we could replace its owl:cardinality property with an owl:qualifiedCardinality property, and add the appropriate owl:onClass property. Here's some Java code that does just that:

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;
import com.hp.hpl.jena.rdf.model.Property;
import com.hp.hpl.jena.vocabulary.OWL;
import com.hp.hpl.jena.vocabulary.OWL2;

public class QualifiedRestrictionExample {
    public static OntClass createCardinalityQRestriction(
            OntModel model,
            String uri,
            Property prop,
            int cardinality, 
            OntClass clas ) {
        OntClass klass = model.createCardinalityRestriction( uri, prop, cardinality );
        klass.removeAll( OWL.cardinality );
        klass.addLiteral( OWL2.qualifiedCardinality, cardinality );
        klass.addProperty( OWL2.onClass, clas );
        return klass;
    }

    public static void main(String[] args) {
        String NS = "https://stackoverflow.com/q/20562107/1281433/";
        OntModel model = ModelFactory.createOntologyModel( OntModelSpec.OWL_DL_MEM );
        OntClass test = model.createClass( NS+"Test" );
        OntProperty j = model.createObjectProperty( NS+"JeVysledkom" );
        OntClass k = model.createClass( NS+"Kolik_Fazovy" );
        OntClass x = createCardinalityQRestriction(model, null, j, 1, k);
        test.addSuperClass( x );
        model.write( System.out, "RDF/XML-ABBREV" );
    }
}

Output:

<rdf:RDF
    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
    xmlns:owl="http://www.w3.org/2002/07/owl#"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema#"
    xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#">
  <owl:Class rdf:about="https://stackoverflow.com/q/20562107/1281433/Kolik_Fazovy"/>
  <owl:Class rdf:about="https://stackoverflow.com/q/20562107/1281433/Test">
    <rdfs:subClassOf>
      <owl:Restriction>
        <owl:onClass rdf:resource="https://stackoverflow.com/q/20562107/1281433/Kolik_Fazovy"/>
        <owl:qualifiedCardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#long"
        >1</owl:qualifiedCardinality>
        <owl:onProperty>
          <owl:ObjectProperty rdf:about="https://stackoverflow.com/q/20562107/1281433/JeVysledkom"/>
        </owl:onProperty>
      </owl:Restriction>
    </rdfs:subClassOf>
  </owl:Class>
</rdf:RDF>

In Protégé:



回答2:

    private void createOneToMany(OntModel ontoModel, OntClass ontoClass, OntProperty prop, Resource resource) {
        OntClass allValuesFromRestriction = ontoModel.createAllValuesFromRestriction(null, prop, resource);
        ontoClass.addSuperClass(allValuesFromRestriction);

        OntClass minCardinalityRestriction = ontoModel.createMinCardinalityRestriction(null, prop, 1);
        ontoClass.addSuperClass(minCardinalityRestriction);
    }

    private void createZeroToMany(OntModel ontoModel, OntClass ontoClass, OntProperty prop, Resource resource) {
        OntClass allValuesFromRestriction = ontoModel.createAllValuesFromRestriction(null, prop, resource);
        ontoClass.addSuperClass(allValuesFromRestriction);

        OntClass minCardinalityRestriction = ontoModel.createMinCardinalityRestriction(null, prop, 0);
        ontoClass.addSuperClass(minCardinalityRestriction);
    }

    private void createZeroToOne(OntModel ontoModel, OntClass ontoClass1, OntProperty prop, OntClass ontoClass2) {

        OntClass minCardinalityRestriction = ontoModel.createMinCardinalityRestriction(null, prop, 0);
        ontoClass1.addSuperClass(minCardinalityRestriction);

        OntClass maxCardinalityRestriction = ontoModel.createMaxCardinalityRestriction(null, prop, 1);
        ontoClass1.addSuperClass(maxCardinalityRestriction);
    }

    private void createOneToOne(OntModel ontoModel, OntClass ontoClass1, OntProperty prop, OntClass ontoClass2) {
        OntClass minCardinalityRestriction = ontoModel.createMinCardinalityRestriction(null, prop, 1);
        ontoClass1.addSuperClass(minCardinalityRestriction);

        OntClass maxCardinalityRestriction = ontoModel.createMaxCardinalityRestriction(null, prop, 1);
        ontoClass1.addSuperClass(maxCardinalityRestriction);
    }

Then you can just do:

OntModel ontModel = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM);
OntClass task = ontModel.createClass(OWL.NS + "Task");
OntClass actor = ontModel.createClass(OWL.NS + "Actor");
OntProperty propTask = ontModel.createObjectProperty( OWL.NS + "Task-performedBy-Actor");
OntProperty propActor = ontModel.createObjectProperty( OWL.NS + "Actor-performs-Task");

To call:

   createOneToMany(ontModel, task, prop, actor);
   createZeroToMany(ontModel, task, prop, actor);
   createOneToOne(ontModel, task, propTask, actor);
   createZeroToOne(ontModel, actor, propActor, task);

Sample of result:

<rdf:RDF
    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
    xmlns:owl="http://www.w3.org/2002/07/owl#"
    xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema#">
  <owl:Class rdf:about="http://www.w3.org/2002/07/owl#Task">
    <rdfs:subClassOf>
      <owl:Restriction rdf:nodeID="A0">
        <owl:minCardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#int"
        >1</owl:minCardinality>
        <owl:onProperty>
          <owl:ObjectProperty rdf:about="http://www.w3.org/2002/07/owl#Actor-performs-Task"/>
        </owl:onProperty>
      </owl:Restriction>
    </rdfs:subClassOf>
  </owl:Class>
  <owl:Class rdf:about="http://www.w3.org/2002/07/owl#Actor">
    <rdfs:subClassOf>
      <owl:Restriction>
        <owl:maxCardinality rdf:datatype="http://www.w3.org/2001/XMLSchema#int"
        >1</owl:maxCardinality>
        <owl:onProperty rdf:resource="http://www.w3.org/2002/07/owl#Actor-performs-Task"/>
      </owl:Restriction>
    </rdfs:subClassOf>
    <rdfs:subClassOf rdf:nodeID="A0"/>
  </owl:Class>
  <owl:ObjectProperty rdf:about="http://www.w3.org/2002/07/owl#Task-performedBy-Actor"/>
</rdf:RDF>


回答3:

Now there is also ONT-API, which is Jena extension for OWL2:

        String ns = "https://stackoverflow.com/q/20562107/1281433/";
        OntGraphModel model = OntModelFactory.createModel()
                .setNsPrefixes(OntModelFactory.STANDARD)
                .setNsPrefix("test", ns);

        OntClass c = model.createOntEntity(OntClass.class, ns + "Kolik_Fazovy");
        OntNOP p = model.createOntEntity(OntNOP.class, ns + "JeVysledkom");
        model.createOntEntity(OntClass.class, ns + "Test")
                .addSubClassOf(model.createObjectCardinality(p, 1, c));

        model.write(System.out, "ttl");