Sparql servers, part 2.

Now then!

Having my basic little graphs, I want to jam in some inferencing rules. I want particularly to use the Pellet reasoning engine. Pellet does OWL2, which will be needed to pull out our accepted taxonomies are buried inside reified relationship objects. See this post for how to convert a reified relationship into an OWL property with conditional OWL2 property chains.

Now, I might warn you that I am writing this post as I go, so it will be a bit stream-of-conciousness.

As far as I can tell, the way inferencing engines work in jena is that they look like a graph. You give them a graph containing your vocabulary and a base graph, and they pass-through the base graph and also generate virtual triples as required.

I’ll start with a very, very simple rule: “hasName” is a sub property of “virtualHasName”. A reasoner should deduce that “#A has-name ‘My name is A'” implies “a virtual-has-name ‘My name is A'”. If we ask the graph for ?s virtual-has-name ?o, we should get ?s=#A, ?o=’My name is A’.

First, a graph containing the rule. I’ll use the “load a resource from a file” graph, rather the putting it in the database. This will reflect what we will want to eventually be doing- editing vocabulary documents with protege and uploading them.

I shall use turtle, which jena seems most comfortable with. The ontology and its inference rules becomes

@prefix owl: <> .
@prefix rdf: <> .
@prefix rdfs: <> .
@base <> .
@prefix : <> .

<> rdf:type owl:Ontology .

    rdf:type owl:DatatypeProperty .

    rdf:type owl:DatatypeProperty ;
    rdfs:subPropertyOf :inferredName .

Great! Now explain to jena that it should be loaded as a graph:

<simpleVoc> rdf:type ja:FileModel    
    ; ja:directory  
    ; ja:modelName "voc.ttl" 

Well! That seemed to work ok. I’ll expose it as a named graph in our dataset, called . This step shouldn’t be necessary to get an inference engine going, but it is necessary to see it directly with the sparql server, and I want to check that the graph loaded as I think it should have.

select ?s ?o ?p where { graph <; { ?s ?p ?o } }

Yay! it’s all there.

Right. Now for the unpleasant bit.

Jena has an inbuilt ontology engine. I suspect that it’s not powerful enough to do property chains – which we will eventually require. But I’ll use it as a first stage.

… hmm. Not so simple as it sounds. The docs are written mainly in terms of building jena engines inside Java, not in therms of the assembler description. And there’s a plethora of engines and options to choose from.

Maybe this will be more helpful. Hmm. It rather looks like these things aren’t going to be anywhere near as powerful a we need. They – for instance – have a specific constant for “a reasoner that does transitive class membership”. Ew! I would have thought that that kinda goes without saying.

Maybe I should bite the bullet and go staring to pellet.

Configuring Joseki + Pellet + TDB. Sounds good. The first sentence is promising: “This page describes how to set up a SPARQL endpoint that can process standard SPARQL queries and return results that include inferences provided by a server-side Pellet reasoner.”. Well, hot diggety, that’s exactly what we are trying to do.

“TDB” is a graph engine, we are using SDB instead. With luck, we can just ignore the stuff on this page for that layer and below.

Now. Do I have pellet? I have a directory named “pellet-2.2.2”, which sounds good.

2. install TDB – done. I’m using SDB
3. install Joseki – done. Up and running.
4. Configure Joseki to query data in a TDB directory – yep, all going. in effect

5. Configure Joseki to query inferences from data+ontology in a single TDB directory

Ah ha! The meat of the issue.

now, we seem to have this

   a ja:RDFDataset;  
   ja:defaultGraph [
      a ja:InfModel;  
      ja:reasoner [  
         ja:reasonerClass "org.mindswap.pellet.jena.PelletReasonerFactory";  

Looks good. I’m surprised that it doest separate the vocabulary and the base data, though. Still, it seems pretty straightforward. The class path gear seems to want to just grab all the jars from the pellet lib directory but not its subdirectories. So I’ll just put symlinks in the joseki lib directory. Remove the “servlet.jar” symlink, because we are using joseki as the servlet. Now does joseki still go? … yes. Good.

Let’s add the pellet gear, just over the union graph. Still going? … why, yes!

Lets expose the pellet graph as a joseki named graph called Still going? … boom!
Caused by: java.lang.ClassCastException: com.hp.hpl.jena.sparql.core.DataSourceImpl cannot be cast to com.hp.hpl.jena.rdf.model.Model

OK. Ah. In the example, there is a “dataset” wrapped around an unnamed pellet graph. I need to remove one layer of wrapping.

 rdf:type ja:InfModel;  
    ja:reasoner [  
        ja:reasonerClass "org.mindswap.pellet.jena.PelletReasonerFactory";  
    ja:baseModel <#union_graph>

Runs now? … yes! Can I see this as a new named graph? …

Yow! Not only is it there, but pellet has done a whole bunch of work, inferring that voc#name is a data property, that A, B and C owl:Things and so on.

Riight. Now – attaching the vocabulary. I’d like to be able to provide it as a separate graph … but I can do it as a union easily enough.

 rdf:type ja:InfModel;  
    ja:reasoner [  
        ja:reasonerClass "org.mindswap.pellet.jena.PelletReasonerFactory";  
    ja:baseModel [
        rdf:type ja:UnionModel    
        ; ja:rootModel <#empty_graph>
        ; ja:subModel <#union_graph>
        ; ja:subModel <#simpleVoc>    

Runs? … yes! And now for the exciting bit. Are the inferences there?

OMG! It works!

fantastic!. Now then, will it do my very nasty conditional property chain thing?



Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )


Connecting to %s

%d bloggers like this: