Wednesday, August 31, 2005

Jena tip: using resources from different models

This question has been asked on the Jena support list a few times recently, so I guess it would be handy to have an answer that Google can find easily.

I have a quick question regarding the use of constant Property and Resource objects. If I use schemagen to generate constants, is it then safe to use a Property (like petName) created from m_model in a model that is created somewhere else? I guess this isn't really a schemagen question as much as a general Jena question: Is it safe to create a Property/Resource in one model, and then use them to query a different model (obviously conforming to the same ontology)?

Answer: yes, it's perfectly safe provided you understand what's going on (so that you don't get unexpected results).

The trick is to realise that each resource (and property, since properties are resources) has a model to which it belongs. This may be null. If you call a method on a resource to add a value to that resource, the statement that is created will be created in the resource's model. The only reason that resources have model pointers is to allow this style of convenience programming. So for example, you can have:

Resource r = m1.createResource();
r.addProperty( foo, "bar" )
 .addProperty( fu, "baz" );

Which will add two statements with r as subject to model m1. That's the convenience of the convenience API. There's no reason why you can't do:

m2.add( r, foo, bar );

even if r, foo and bar are defined in different models than m2. In particular, if you do the following:

m2.add( r, foo, bar )

you'll get m2 as a result, independently of which model r was defined in.

You may also want to note that Jena's contract for resource equality is that two resources are .equals() if they have the same URI or the same bNode identifier. The models to which they are bound are not part of the equality contract. , .

Thursday, August 18, 2005

Jena tip: ont model specs

I was asked a question on jena-dev that I think bears repeating, since it's fairly frequently asked.

so, my question is, in the case where we need inference capability, if all we need to do is just
OntModel ontModel = ModelFactory.createOntologyModel( OntModelSpec.OWL_MEM_MICRO_RULE_INF );
then why does Jena still provide things like ReasonerRegistry.getOWLReasoner(), ModelFactory.createInfModel , OntModelSpec, etc.?

OK, here's the simple explanation: the first form is exactly the same as the second form, but a bit simpler to use.

Longer explanation: an OntModel has various parameters that allow it to be more flexible when handling ontologies. OntModel can handle OWL, OWL DL, OWL Lite, DAML+OIL and RDFS ontologies. So when you say OntModel.createClass(), it has to know which kind of class (OWL, DAML, etc) to create. This information is conveyed through the OntModelSpec, which contains a language profile. Similarly, an OntModel can have an attached reasoner, or none at all. Which reasoner is attached to the OntModel is also expressed in the OntModelSpec.

A user can, if desired, create an OntModelSpec entirely from scratch, setting each field (profile, reasoner, etc) to the desired value. However, there are some common combinations (e.g. an in-memory model, using OWL, with the MICRO rule reasoner) that we know are going to be re-used many times, so we've taken the trouble to pre-define some constants for commonly used OntModelSpecs. These have suggestive names, so the one I just described is OWL_MEM_MICRO_RULE_INF. But all it is is a pre-defined OntModelSpec with the fields filled-in.

Some fields cannot be filled-in in advance. For example, if the model is in a database, not in memory, then the db type, user-name and password can't be known in advance. Similarly, external reasoners can be at diffenent access URL's. However, in these cases it's still nice to be able to re-use some of the pre-defined common variants, and just adapt them. So you can create a new OntModelSpec using a pre-defined one as a template:

OntModelSpec newSpec = new OntModelSpec( OntModelSpec.OWL_MEM_RULE_INF );

and then just tweak the bits you want to change.

Likewise, the builtin reasoners have a number of configuration options, including which rulesets to use, which rule engine to use, etc. Again, we make it easy to use the common patterns, but provide access to the nuts-and-bolts for those that need them

under what situation do we ever need to use these guys?

Useful heuristic: you probably don't need to use them. When this heuristic breaks (all heuristics break eventually), you'll know that it's time to read up on the details of the low-level interfaces. Until then, don't worry about it! , .