4

I have some data coming in from a RabbitMQ. The data is formatted as triples, so a message from the queue could look something like this:

:Tom foaf:knows :Anna

where : is the standard namespace of the ontology into which I want to import the data, but other prefixes from imports are also possible. The triples consist of subject, property/predicate and object and I know in each message which is which.

On the receiving side, I have a Java program with an OWLOntology object that represents the ontology where the newly arriving triples should be stored temporarily for reasoning and other stuff. I kind of managed to get the triples into a Jena OntModel but that's where it ends. I tried to use OWLRDFConsumer but I could not find anything about how to apply it.

My function looks something like this:

public void addTriple(RDFTriple triple) {

    //OntModel model = ModelFactory.createOntologyModel();

    String subject = triple.getSubject().toString();
    subject = subject.substring(1,subject.length()-1);
    Resource s = ResourceFactory.createResource(subject);

    String predicate = triple.getPredicate().toString();
    predicate = predicate.substring(1,predicate.length()-1);
    Property p = ResourceFactory.createProperty(predicate);

    String object = triple.getObject().toString();
    object = object.substring(1,object.length()-1);
    RDFNode o = ResourceFactory.createResource(object);

    Statement statement = ResourceFactory.createStatement(s, p, o);
    //model.add(statement);

    System.out.println(statement.toString());
}

I did the substring operations because the RDFTriple class adds <> around the arguments of the triple and the constructor of Statement fails as a consequence.

If anybody could point me to an example that would be great. Maybe there's a much better way that I haven't thought of to achieve the same thing?

casualcoder
  • 480
  • 4
  • 17
  • The question title is "How to add RDF triples to an OWLOntology?" and you said in the question that you "managed to get the triples into a Jena OntModel." What else do you need to do? Can you show us what you've done so far? – Joshua Taylor Jul 04 '13 at 13:09
  • Ah, OWLOntology and OWLRDFConsumer are are OWL API classes, so it seems like you're trying to do something with the OWL API. Can you give some more details about what you've done so far? Of interest might also be what you did to get the triples in to the Jena OntModel. – Joshua Taylor Jul 04 '13 at 13:11
  • Yes, sorry I didn't mention they're OWLAPI classes. I've been trying to get it to work and now the act of adding it to the model fails too, I have changed so many things in between that I don't recall the way it works :( I'll add my code to the original question. – casualcoder Jul 04 '13 at 13:25
  • [`RDFTriple`](http://owlapi.sourceforge.net/javadoc/org/semanticweb/owlapi/io/RDFTriple.html) has `RDFResource`s as subject and predicate, and a `RDFNode` as object. If you `getSubject` to get the `RDFResource`, then `getResource` to get the `IRI`, and then use `toString` on that, I think you'll get the IRI text (as opposed to [`toQuotedString`](http://owlapi.sourceforge.net/javadoc/org/semanticweb/owlapi/model/IRI.html#toQuotedString()) which returns the text surrounded by angle brackets. – Joshua Taylor Jul 04 '13 at 13:44
  • I don't have to use RDFTriple. What I get as input is pure JSON, I just thought I should use the RDFTriple class because that's what it is - a triple. Or not? – casualcoder Jul 04 '13 at 13:49

2 Answers2

3

It seems like the OWLRDFConsumer is generally used to connect the RDF parsers with OWL-aware processors. The following code seems to work, though, as I've noted in the comments, there are a couple of places where I needed an argument and put in the only available thing I could.

The following code: creates an ontology; declares two named individuals, Tom and Anna; declares an object property, likes; and declares a data property, age. Once these are declared we print the ontology just to make sure that it's what we expect. Then it creates an OWLRDFConsumer. The consumer constructor needs an ontology, an AnonymousNodeChecker, and an OWLOntologyLoaderConfiguration. For the configuration, I just used one created by the no-argument constructor, and I think that's OK. For the node checker, the only convenient implementer is the TurtleParser, so I created one of those, passing null as the Reader. I think this will be OK, since the parser won't be called to read anything. Then the consumer's handle(IRI,IRI,IRI) and handle(IRI,IRI,OWLLiteral) methods are used to process triples one at a time. We add the triples

:Tom :likes :Anna
:Tom :age 35

and then print out the ontology again to ensure that the assertions got added. Since you've already been getting the RDFTriples, you should be able to pull out the arguments that handle() needs. Before processing the triples, the ontology contained:

<NamedIndividual rdf:about="http://example.org/Tom"/>

and afterward this:

<NamedIndividual rdf:about="http://example.org/Tom">
  <example:age rdf:datatype="http://www.w3.org/2001/XMLSchema#integer">35</example:age>
  <example:likes rdf:resource="http://example.org/Anna"/>
</NamedIndividual>

Here's the code:

import java.io.Reader;

import org.coode.owlapi.rdfxml.parser.OWLRDFConsumer;
import org.semanticweb.owlapi.apibinding.OWLManager;
import org.semanticweb.owlapi.model.IRI;
import org.semanticweb.owlapi.model.OWLDataFactory;
import org.semanticweb.owlapi.model.OWLDataProperty;
import org.semanticweb.owlapi.model.OWLEntity;
import org.semanticweb.owlapi.model.OWLNamedIndividual;
import org.semanticweb.owlapi.model.OWLObjectProperty;
import org.semanticweb.owlapi.model.OWLOntology;
import org.semanticweb.owlapi.model.OWLOntologyCreationException;
import org.semanticweb.owlapi.model.OWLOntologyLoaderConfiguration;
import org.semanticweb.owlapi.model.OWLOntologyManager;
import org.semanticweb.owlapi.model.OWLOntologyStorageException;

import uk.ac.manchester.cs.owl.owlapi.turtle.parser.TurtleParser;


public class ExampleOWLRDFConsumer {
    public static void main(String[] args) throws OWLOntologyCreationException, OWLOntologyStorageException {
        // Create an ontology.
        OWLOntologyManager manager = OWLManager.createOWLOntologyManager();
        OWLDataFactory factory = manager.getOWLDataFactory();
        OWLOntology ontology = manager.createOntology();

        // Create some named individuals and an object property.
        String ns = "http://example.org/";
        OWLNamedIndividual tom = factory.getOWLNamedIndividual( IRI.create( ns+"Tom" ));
        OWLObjectProperty likes = factory.getOWLObjectProperty( IRI.create( ns+"likes" ));
        OWLDataProperty age = factory.getOWLDataProperty( IRI.create( ns+"age" ));
        OWLNamedIndividual anna = factory.getOWLNamedIndividual( IRI.create( ns+"Anna" ));

        // Add the declarations axioms to the ontology so that the triples involving
        // these are understood (otherwise the triples will be ignored).
        for ( OWLEntity entity : new OWLEntity[] { tom, likes, age, anna } ) {
            manager.addAxiom( ontology, factory.getOWLDeclarationAxiom( entity ));
        }

        // Print the the ontology to see that the entities are declared. 
        // The important result is
        //  <NamedIndividual rdf:about="http://example.org/Tom"/>
        // with no properties
        manager.saveOntology( ontology, System.out );

        // Create an OWLRDFConsumer for the ontology.  TurtleParser implements AnonymousNodeChecker, so 
        // it was a candidate for use here (but I make no guarantees about whether it's appropriate to 
        // do this).  Since it won't be reading anything, we pass it a null InputStream, and this doesn't
        // *seem* to cause any problem.  Hopefully the default OWLOntologyLoaderConfiguration is OK, too.
        OWLRDFConsumer consumer = new OWLRDFConsumer( ontology, new TurtleParser((Reader) null), new OWLOntologyLoaderConfiguration() );

        // The consumer handles (IRI,IRI,IRI) and (IRI,IRI,OWLLiteral) triples.
        consumer.handle( tom.getIRI(), likes.getIRI(), anna.getIRI() );
        consumer.handle( tom.getIRI(), age.getIRI(), factory.getOWLLiteral( 35 ));

        // Print the ontology to see the new object and data property assertions.  The import contents is
        // still Tom: 
        //   <NamedIndividual rdf:about="http://example.org/Tom">
        //     <example:age rdf:datatype="http://www.w3.org/2001/XMLSchema#integer">35</example:age>
        //     <example:likes rdf:resource="http://example.org/Anna"/>
        //  </NamedIndividual>
        manager.saveOntology( ontology, System.out );
    }
}
Joshua Taylor
  • 84,998
  • 9
  • 154
  • 353
  • First of all thanks a lot for your effort. I think you slightly misunderstood what I'm doing, I try to be more precise: The triples I get are heterogeneous if you like. I never know what kind of relationship they describe. In your example, you have to manually create the OWLObjectProperty/OWLDataProperty/... - classes. My problem is that I don't know in advance what they are and I was hoping to find an automated way of adding them to the existing ontology. If that's not possible I'll have to go back and have the JSON producer add the type of relationship to the triples (then quadruples?) – casualcoder Jul 04 '13 at 15:14
  • @casualcoder I assumed that they were going to already be declared in your ontology. The only reason I included them here is because the the OWLRDFConsumer won't handle a triple if it can't figure out what's supposed to be asserted. The idea here is that once you've got your ontology, you just create the consumer and call its handle method. In this example you could have just as well loaded the initial file from the ontology, and just called handle with the IRIs for the individuals. The _only_ reason this code has declaration axioms, etc., is so that it's a minimal working example. – Joshua Taylor Jul 04 '13 at 15:17
  • @casualcoder To clarify, the handle method just IRIs, which as we see in your Java based code, you can get. Since you've already got the OWLOntology `ontology` somewhere, you just create the the OWLRDFConsumer with it (and the TurtleParser and LoaderConfiguration) and then have your addTriple() call the consumer's handle() instead of model.add(). – Joshua Taylor Jul 04 '13 at 15:21
  • Oh my bad. Sorry, after 8 hours of thinking about the same thing my brain is about to explode. You're right, I already have all of that in my ontology and your answer is exactly what I've been looking for. – casualcoder Jul 04 '13 at 15:22
  • @casualcoder Glad to hear it! It's much harder to process OWL triple by triple, because so much depends on context. For instance, we _can't_ process something like _Tom likes Anna_ without knowing whether _likes_ is an annotation or an object property. Triple-based processing is a bit more suitable for object and datatype property assertions though, as we're doing in this case. – Joshua Taylor Jul 04 '13 at 15:48
  • Since I don't use annotations in this specific ontology, it's only going to be class assertions, data- and object properties. I chose to do the triple based processing to equalise the input so any source can add triples to the queue while the consumer can stay the same. – casualcoder Jul 05 '13 at 08:03
  • @casualcoder Right, I was just pointing out that there are some OWL constructs that you won't be able to handle based on a triple by triple processing. If you're just updating the ground knowledge with property assertions (for known properties and individuals), I think you'll be fine. – Joshua Taylor Jul 05 '13 at 13:35
0

In ONT-API, which is an extended Jena-based implementation of OWL-API, it is quite simple:

    OWLOntologyManager manager = OntManagers.createONT();
    OWLOntology ontology = manager.createOntology(IRI.create("http://example.com#test"));
    ((Ontology)ontology).asGraphModel().createResource("http://example.com#clazz1").addProperty(RDF.type, OWL.Class);
    ontology.axioms(AxiomType.DECLARATION).forEach(System.out::println);

For more information see ONT-API wiki, examples

ssz
  • 835
  • 1
  • 6
  • 18