Jena's rule for validation in ontology

I want to check the ontology and throw an error if something is wrong.

The most important check I have to do is as follows: I have a class like this:

   <owl:Class rdf:about="&schema;ExampleClass">
        <rdfs:subClassOf rdf:resource="&schema;SuperClass"/>
        <rdfs:subClassOf>
            <owl:Restriction>
                <owl:onProperty rdf:resource="&schema;myProperty"/>
                <owl:onClass rdf:resource="&schema;OtherClass"/>
                <owl:qualifiedCardinality rdf:datatype="&xsd;nonNegativeInteger">1</owl:qualifiedCardinality>
            </owl:Restriction>
        </rdfs:subClassOf>
    </owl:Class>

      

(The interesting part is the 2nd subClassOf.) In Protege, that means ExampleClass is subClass of myProperty exactly 1 OtherClass

.

So, I want to check that there is only one myProperty with a value: person of type OtherClass.

Can such rules be asserted? It would be perfect if there was a rule to do this for all classes with this modeling (and possibly with at least 1, exactly 2, ...)

Another question: is there a ready-made closed world mind that does exactly this for me?

+3


source to share


2 answers


Your example doesn't depend on using the closed world principle. It depends on the introduction of the validation rule for owl:qualifiedCardinality

.

For example, take the following example input file:

@prefix xsd:  <http://www.w3.org/2001/XMLSchema#>.
@prefix rdf:  <http://www.w3.org/1999/02/22-rdf-syntax-ns#>.
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>.
@prefix owl:  <http://www.w3.org/2002/07/owl#>.
@prefix : <urn:x-so:ex#>.

:OtherClass a owl:Class .
:SuperClass a owl:Class .

:myProperty a rdf:Property
          ; rdfs:range  :OtherClass
          .

:ExampleClass rdfs:subClassOf :SuperClass
            ; rdfs:subClassOf [ a owl:Restriction
                              ; owl:onProperty :myProperty
                              ; owl:cardinality 1
#                             ; owl:onClass :OtherClass
#                             ; owl:qualifiedCardinality 1
                              ]
            .


:o0 a :OtherClass .
:o1 a :OtherClass .

:s0 rdf:type    :ExampleClass
  ; :myProperty :o0
  ; :myProperty :o1
  .

      

Pay attention to the commented lines and the entered axiom above them. This ontology is owl-1 compatible, so there are validation rules for it. There is no validation error in the next test, why? because we can conclude that, for example :o0 owl:sameAs :o1

, that does not lead to a contradiction.

final Model baseModel = ModelFactory.createDefaultModel();
try( final InputStream in = this.getClass().getResourceAsStream("/so.ttl") ){
    baseModel.read(in, null, "TTL");
}
final OntModel model  = ModelFactory.createOntologyModel(OntModelSpec.OWL_DL_MEM_RULE_INF, baseModel);

assertTrue(model.contains(s0, myProperty, o0));
assertTrue(model.contains(s0, myProperty, o1));

final ValidityReport report = model.validate();
assertTrue( report.isValid() );

      

In the next example, however, we will show that if we introduce :o0 owl:differentFrom :o1

, we get a contradiction:

final Model baseModel = ModelFactory.createDefaultModel();
try( final InputStream in = this.getClass().getResourceAsStream("/so.ttl") ){
    baseModel.read(in, null, "TTL");
}
final OntModel model  = ModelFactory.createOntologyModel(OntModelSpec.OWL_DL_MEM_RULE_INF, baseModel);
model.add(o1, OWL.differentFrom, o0); // NOTE!!
assertTrue(model.contains(s0, myProperty, o0));
assertTrue(model.contains(s0, myProperty, o1));

final ValidityReport report = model.validate();
assertFalse( report.isValid() );

      

Given the scenario demonstrated, I would suggest the following solutions (in order of increasing complexity):

Solution 1: Open-World with OWL 1 restrictions

Express your ontology in terms of owl-1 constraints if possible, and then you can use existing rulesets to validate.

Solution 2: Open-World with OWL 2 add-ons

It won't be easy. Take a look at etc/owl-fb.rules

in jena-core

and you will notice that support for some of the generic owl constructs (primarily power) required Jena Builtin to develop to make the rule expression simple. I have linked to another answer regarding inline functions if this is the direction you intend to go.



The following rules are taken from the jena-core

etc/owl-fb.rules

cardinality file . They are not a complete set of power rules.

[restriction5: (?C owl:onProperty ?P), (?C owl:cardinality ?X)
  -> (?C owl:equivalentClass card(?P, ?X)),
     (?C rdfs:subClassOf min(?P, ?X)),
     (?C rdfs:subClassOf max(?P, ?X)) ]

[restriction4: (?C owl:onProperty ?P), (?C owl:maxCardinality ?X)
  -> (?C owl:equivalentClass max(?P, ?X)) ]

[validationMaxN: (?v rb:validation on()), (?C rdfs:subClassOf max(?P, ?N)) greaterThan(?N, 1) (?P rdf:type owl:DatatypeProperty) ->
    [max2b: (?X rb:violation error('too many values', 'Too many values on max-N property (prop, class)', ?P, ?C))
          <- (?X rdf:type ?C), countLiteralValues(?X, ?P, ?M), lessThan(?N, ?M)  ] ]

      

restriction5

simply defines cardinality in terms of min and max cardinality ( min

and max

are functors in this example). validationMaxN

is a specific rule (for N> 1) that shows how a violation can be identified. It delegates CountLiteralValues

to determine the number of bindings that exist for this property.

If you want to introduce CountQualifiedValues

Builtin, then you can define a set of rules like the following to introduce new axioms:

[restriction4: (?C owl:onProperty ?P), (?C owl:maxQualifiedCardinality ?X), (?C owl:onClass ?Y)
  -> (?C owl:equivalentClass max(?P, ?X, ?Y)) ]

[validationMaxN: (?v rb:validation on()), (?C rdfs:subClassOf max(?P, ?N, ?Y)) greaterThan(?N, 1) (?P rdf:type owl:ObjectProperty) ->
    [max2b: (?X rb:violation error('too many values', 'Too many values on max-QN property (prop, class, qclass)', ?P, ?C, ?Y))
          <- (?X rdf:type ?C), countQualifiedValues(?X, ?P, ?Y, ?M), lessThan(?N, ?M)  ] ]

      

Solution 3: Closed world with OWL 2 add-ons

This is not really all that differs from solution 2. However, you will try to define alternative semantics for OWL constructs, which is not a trivial task. You can put in some validation rules (read etc/owl-fb.rules

for examples) that capture your specific closed assumptions. If you enforce them to be restricted to only in use (?v rb:validation on())

, you can ensure that you are only executing a closed world when you do the check.

Side discussion

Here is an example of a power limitation expressed in owl 1. This is the same as in the input file above. This is expressed in syntax TURTLE

and is trivial to convert to RDF/XML

or any other valid serialization RDF

.

:ExampleClass rdfs:subClassOf :SuperClass
            ; rdfs:subClassOf [ a owl:Restriction
                              ; owl:onProperty :myProperty
                              ; owl:cardinality 1
                              ]
            .

      

This pair of restrictions is not exactly semantically equivalent owl:qualifiedCardinality

, but if you have the ability to change your domain model, you can often work around it.

For example, owl:qualifiedCardinality

it's great to say things like :People :haveBodyPart exactly 2 :Eyes

. The OWL 1 workaround could be, for example, to create :haveEye rdfs:subPropertyOf :haveBodyPart

and then say :People :haveEye exactly 2

(no qualified power limitation)

+6


source


It looks like you are trying to test some integrity constraints based on some of the OWL axioms, but it is important to note that OWL is based on the open world assumption. This means that even if you have:

Person & sqsubseteq; & Exist; hasParent.Person

which says that every person has (at least) one hasParent property value with a value that is another Person, you can still have a consistent ontology that doesn't include any hasParent statements at all! So the kind of "validation" you're looking for really has more to do with a closed world and full interpretation.

Rather than using a rules-based approach, I would probably attack this issue by using some SPARQL queries to test people who are not satisfying what we expect them to be. For example, in this case, you can write a general rule that considers individuals to be instances of the constraint, and then you can check to see if you can find triplets in the data that "match" the constraint.

In this particular case, you can find (some) instances of (myProperty exactly 1 OtherClass) (and qualified cardinality in general) with:

?instance a [ owl:onProperty ?property ;
              owl:onClass ?class ;
              owl:qualifiedCardinality ?cardinality ] .

      



Of course, if some individual can only be inferred as an instance of a class, this template will not find it, but we assume that you are working with private and complete data, so something like that should work. ("Something like" might include ?instance a/rdfs:subClassOf* [ ... ]

.) Once you get that, you can write a subquery that checks if the data matches:

select ?instance ?property ?class (count(?value) as ?actualCardinality) where {
  ?instance ?property ?value .
  ?value a ?class
}
group by ?instance ?property ?class 

      

Then you can combine them to identify people where "actual cardinality" doesn't match? power:

select ?instance
       ?property
       ?class
       ?cardinality
       (count(?value) as ?actualCardinality)
where {
  ?instance a [ owl:onProperty ?property ;
                owl:onClass ?class ;
                owl:qualifiedCardinality ?cardinality ] .

  ?instance ?property ?value .
  ?value a ?class
}
group by ?instance ?property ?class ?cardinality
having ( ?cardinality != ?actualCardinality )

      

I haven't tested anything yet, so there might be typos and you haven't provided the complete details, so I can't test it either, but something on that general line should work.

+4


source







All Articles