This project has retired. For details please refer to its Attic page.
Apache Stanbol - Apache Stanbol Reasoners

Apache Stanbol Reasoners

The Stanbol Reasoners component provides a set of services that take advantage of automatic inference engines.

The module implements a common api for reasoning services, providing the possibility to plug different reasoners and configurations in parallel.

Actually the module includes OWLApi and Jena based abstract services, with concrete implementations for Jena RDFS, OWL, OWLMini and HermiT reasoning service.

The Reasoners module expose a REST endpoint at the following location:

http://localhost:8080/reasoners

with the following preloaded services:

In addition, it is also available a service which uses the HermiT [6] reasoner to exploit the full OWL 2 [3] specification.

Each reasoner can be accessed with one of three tasks:

For example:

http://localhost:8080/reasoners/owl/check // expose the Jena owl service with task check, or
http://localhost:8080/reasoners/owl2/classify // to use the HermiT service with task classify

We can use the curl command line utility to ask the Jena OWL reasoning service to materialize all inferences produced by loading the FOAF ontology:

$ curl -H "Accept: text/n3" "http://localhost:8080/stanbol/reasoners/owl/enrich?url=http://xmlns.com/foaf/0.1/"

The above example performs a GET asking for a text/n3 representation of the result. For example, the equivalency of foaf:Agent and dc:Agent result in the rdfs:subClassOf statements for the foaf:Person type:

Differences between the reasoners

Let's give some example on the differences between the available reasoners (to try the example ontology snippets you can download them from here).

The first snippet uses rdfs:subClassOf to declare that any Article is a Document, which is in turn a ContentItem.

<!-- item_1 is an Article -->
<ex:Article rdf:about="http://www.example.org/reasoners/item_1"/>

<!-- An article is a kind of Document --> <rdf:Description rdf:about="http://www.example.org/reasoners/Article"> <rdfs:subClassOf rdf:resource="http://www.example.org/reasoners/Document"/> </rdf:Description>

<!-- An document is a kind of content item --> <rdf:Description rdf:about="http://www.example.org/reasoners/Document"> <rdfs:subClassOf rdf:resource="http://www.example.org/reasoners/ContentItem"/> </rdf:Description>

download it

Giving it to the /rdfs reasoning service, we obtain as resulted inferred statement that item_1 is also a Document and a ContentItem. Another feature of RDFS is the definition of the domain and range of a property.

<!-- Both enridaga and alexdma are authors of item_1 -->
<rdf:Description rdf:about="http://www.example.org/reasoners/enridaga">
    <ex:author rdf:resource="http://www.example.org/reasoners/item_1"/>
</rdf:Description>
<rdf:Description rdf:about="http://www.example.org/reasoners/alexdma">
    <ex:author rdf:resource="http://www.example.org/reasoners/item_1"/>
</rdf:Description>

<!-- ex:author wants a person as subject, and a content-item as object --> <rdf:Description rdf:about="http://www.example.org/reasoners/author"> <rdfs:domain rdf:resource="http://www.example.org/reasoners/Person"/> <rdfs:range rdf:resource="http://www.example.org/reasoners/ContentItem"/> </rdf:Description>

download it We will obtain, in this case, that both enridaga and alexdma are Authors, and that item_1 is a ContentItem. RDFS semantics is considered also by other reasoners. The /rdfs service is the less "expressive" of the four.

The following snippet will work with /owl, /owlmini and /owl2 (but not with /rdfs):

<!-- ogrisel, enridaga and alexdma are developers -->
<ex:Developer rdf:about="#enridaga" />
<ex:Developer rdf:about="#ogrisel" />
<ex:Developer rdf:about="#alexdma" />

<!-- We know: #alexdma #workedTogheter #enridaga and #ogrisel --> <rdf:Description rdf:about="#alexdma"> <workedTogheter rdf:resource="#ogrisel"/> <workedTogheter rdf:resource="#enridaga"/> </rdf:Description>

<!-- #workedTogheter is an owl:SymmetricProperty (well, this is an example...) --> <owl:SymmetricProperty rdf:about="#workedTogheter"/> <!-- #workedTogheter is also a owl:TransitiveProperty (well, this is an example...) --> <owl:TransitiveProperty rdf:about="#workedTogheter"/>

download it The OWL vocabulary introduce logical capabilities, allowing more complex inferences to be produced. In the above example we state that alexdma workedWith enridaga and ogrisel. Since we declare the property workedTogheter to be "Symmetric" and "Transitive", the result will include the following:

Next snippet is inconsistent. This means that the OWL based reasoners will not return any inference, but a 204 HTTP response:

<!-- enridaga is a person -->
<ex:Person rdf:about="http://www.example.org/reasoners/enridaga" />

<!-- Persons and Organizations are disjoint --> <owl:Class rdf:about="http://www.example.org/reasoners/Person" /> <owl:Class rdf:about="http://www.example.org/reasoners/Organization"> <owl:disjointWith rdf:resource="http://www.example.org/reasoners/Person" /> </owl:Class>

<!-- A Public Limited Company is a kind of Company, which is a kind of Organization --> <owl:Class rdf:about="http://www.example.org/reasoners/PublicLimitedCompany"> <rdfs:subClassOf rdf:resource="http://www.example.org/reasoners/Company" /> </owl:Class> <owl:Class rdf:about="http://www.example.org/reasoners/Company"> <rdfs:subClassOf rdf:resource="http://www.example.org/reasoners/Organization" /> </owl:Class>

<!-- enridaga cannot be a Public Limited Company --> <ex:PublicLimitedCompany rdf:about="http://www.example.org/reasoners/enridaga" />

download it The /owlmini implements the OWL language with some (more) limitations then /owl (both are based on the Jena rule based reasoner, as said before).

The following example shows the use of class restrictions, in particular the usage of owl:someValuesFrom:

<!-- john, is an developer, but we don't know anything else -->
<ex:Developer rdf:about="#john">
</ex:Developer>

<!-- a #SoftwareCompany is a kind of #Organization --> <owl:Class rdf:about="SoftwareCompany"> <rdfs:subClassOf rdf:resource="#Organization" /> </owl:Class>

<!-- #Developers #worksAt some #SoftwareCompany (they are not the only one..., this is why we use owl:subClassOf) --> <owl:Class rdf:about="#Developer"> <rdfs:subClassOf> <owl:restriction> <owl:onProperty rdf:resource="#worksAt" /> <owl:someValuesFrom rdf:resource="#SoftwareCompany" /> </owl:restriction> </rdfs:subClassOf> </owl:Class>

<!-- Employees are all who #worksAt any kind of Organization (owl:equivalentClass) --> <owl:Class rdf:about="#Employee"> <owl:equivalentClass> <owl:restriction> <owl:onProperty rdf:resource="#worksAt" /> <owl:someValuesFrom rdf:resource="#Organization" /> </owl:restriction> </owl:equivalentClass> </owl:Class>

download it

We expect an OWL reasoner to state that John is an Employee. This example does not work with /rdfs (it ignores the OWL semantics), and does not work with /owlmini, because the Jena OWL(mini) reasoner omits the forward entailments for owl:someValuesFrom restrictions (see [4]). It works correctly if we use the service /owl.

The /owl service support the most of the semantic of OWL. The HermiT reasoner is based on OWLApi and is an example of a DL reasoner. It fully covers OWL and OWL2, which introduces lot of interesting features. Here is an example:

<!-- any Employee must have some features: firstname, familyname, email 
    and worksAt (in one of the allowed places) -->
<owl:Class rdf:about="#Employee">
    <owl:equivalentClass>
        <owl:Class>
            <owl:intersectionOf rdf:parseType="Collection">
                <rdf:Description rdf:about="#Person" />
                <owl:Restriction>
                    <owl:onProperty rdf:resource="#firstname" />
                    <owl:someValuesFrom rdf:resource="&rdfs;Literal" />
                </owl:Restriction>
                <owl:Restriction>
                    <owl:onProperty rdf:resource="#familyname" />
                    <owl:someValuesFrom rdf:resource="&rdfs;Literal" />
                </owl:Restriction>
                <owl:Restriction>
                    <owl:onProperty rdf:resource="#email" />
                    <owl:someValuesFrom rdf:resource="&rdfs;Literal" />
                </owl:Restriction>
                <!-- -->
                <!-- Let's say that Employees can work only in #Rome , #Catania and 
                    #Bologna -->
                <owl:Restriction>
                    <owl:onProperty rdf:resource="#worksAt" />
                    <owl:someValuesFrom>
                        <owl:Class>
                            <owl:oneOf rdf:parseType="Collection">
                                <owl:Thing rdf:about="#Rome" />
                                <owl:Thing rdf:about="#Catania" />
                                <owl:Thing rdf:about="#Bologna" />
                            </owl:oneOf>
                        </owl:Class>
                    </owl:someValuesFrom>
                </owl:Restriction>
            </owl:intersectionOf>
        </owl:Class>
    </owl:equivalentClass>
</owl:Class>

<owl:DatatypeProperty rdf:about="#firstname" /> <owl:DatatypeProperty rdf:about="#familyname" /> <owl:DatatypeProperty rdf:about="#email" />

<!-- #worksAt has range #Place --> <owl:ObjectProperty rdf:about="#worksAt"> <rdfs:range rdf:resource="#Place" /> </owl:ObjectProperty>

<!-- all the following places are distinct (no synonyms here) --> <owl:AllDifferent> <owl:distinctMembers rdf:parseType="Collection"> <owl:Thing rdf:about="#Rome" /> <owl:Thing rdf:about="#Catania" /> <owl:Thing rdf:about="#Bologna" /> <owl:Thing rdf:about="#Moricone" /> </owl:distinctMembers> </owl:AllDifferent>

<!-- enridaga, to be an Employee, must fulfill the restrictions defined for the class #Employee. --> <Person rdf:about="#enridaga"> <!-- If you comment one of the next 4 statement, you won't have #enridaga to result as #Employee. --> <firstname>Enrico</firstname> <familyname>Daga</familyname> <email>enridaga@example.org</email> <worksAt rdf:resource="#Catania" /> <!-- If you uncomment the two statements below you will obtain an inconsistency, because #Moricone is not an allowed place for developers --> <!-- <worksAt rdf:resource="#Moricone" /> <rdf:type rdf:resource="#Employee" /> --> </Person>

download it

The above differences depend on the semantic supported by the specific reasoner and from the implementation, which limit the power of the system in favour of a better efficiency (is the case of the /owlmini implementation of Jena, more efficient then the respective /owl). If you need to work with RDFS semantic, and don't need OWL for your inferences, just use the RDFS one.

Build and install

Run Stanbol, for example:

$ java -jar -Xmx1g org.apache.stanbol.launchers.full-0.9.0-incubating-SNAPSHOT.jar

You must have the Ontonet and Rules modules already installed (they are if you have followed the above example). Move to the /reasoners directory, then run

$ mvn install -PinstallBundle -Dsling.url=&lt;the path to your running Felix administration console&gt;

for example

% mvn install -PinstallBundle http://localhost:8080/system/console

Add the HermiT reasoner

To enable HermiT as OWL2 reasoner you can download and install it from the Stanbol (Incubating) svn repository. The steps are the following:

$ svn co https://svn.apache.org/repos/asf/incubator/stanbol/trunk/reasoners/hermit stanbol-hermit
$ cd stanbol-hermit
$ mvn install -PinstallBundle -Dsling.url=http://localhost:8080/system/console // change this to the path related to your Stanbol instance

References:


Back to components