Thank you! That was what I needed and I have learned quite a bit.

Here is the rule I ended up using:

@prefix ro: <http://example.com/ont/roster/>.
>
>  [r1: (?x rdf:type ro:RosterEntry), (?x ro:hasSignature ?sig), regex(?sig,
> '(.*) (.*)', ?first, ?last), uriConcat('
> http://example.com/ont/roster/people/', ?first, ?last, ?y) -> (?y
> ro:hasFirstName ?first),  (?y ro:hasLastName ?last),  (?y rdf:type
> ro:Person)]


With that rule, the inferred model contains:

http://example.com/ont/roster/people/BobSmith type Person .
> http://example.com/ont/roster/people/BobSmith hasLastName "Smith" .
> http://example.com/ont/roster/people/BobSmith hasFirstName "Bob" .
> http://example.com/ont/roster/people/SallyJones type Person .
> http://example.com/ont/roster/people/SallyJones hasLastName "Jones" .
> http://example.com/ont/roster/people/SallyJones hasFirstName "Sally" .
> http://example.com/ont/roster/ versionIRI .
> http://example.com/ont/roster/ type Ontology .
> http://example.com/ont/roster/RosterEntry type Class .
> http://example.com/ont/roster/bobEntry hasSignature "Bob Smith" .
> http://example.com/ont/roster/bobEntry type RosterEntry .
> http://example.com/ont/roster/bobEntry type NamedIndividual .
> http://example.com/ont/roster/Person type Class .
> http://example.com/ont/roster/hasLastName range string .
> http://example.com/ont/roster/hasLastName domain Person .
> http://example.com/ont/roster/hasLastName type DatatypeProperty .
> http://example.com/ont/roster/sallyEntry hasSignature "Sally Jones" .
> http://example.com/ont/roster/sallyEntry type RosterEntry .
> http://example.com/ont/roster/sallyEntry type NamedIndividual .
> http://example.com/ont/roster/hasSignature range string .
> http://example.com/ont/roster/hasSignature domain RosterEntry .
> http://example.com/ont/roster/hasSignature type DatatypeProperty .
> http://example.com/ont/roster/hasFirstName range string .
> http://example.com/ont/roster/hasFirstName domain Person .
> http://example.com/ont/roster/hasFirstName type DatatypeProperty .


On Wed, May 27, 2020 at 2:14 AM Dave Reynolds <dave.e.reyno...@gmail.com>
wrote:

> On 27/05/2020 04:54, Kenneth Keefe wrote:
> > Thank you! Can you suggest any texts that teach how to effectively write
> > inference rules for Jena?
>
> I don't know of any though no doubt there's the odd blog post example.
>
> > However, I'm not having success changing the node URIs. When I change the
> > rule to this:
> >
> >   [r1: (?x rdf:type ro:RosterEntry), (?x ro:hasSignature ?sig),
> regex(?sig,
> >> '(.*) (.*)', ?first, ?last), makeSkolem(?y, ?x), uriConcat('
> >> http://example.com/ont/roster/people/', ?first, ?last, ?y) -> (?y
> >> ro:hasFirstName ?first),  (?y ro:hasLastName ?last),  (?y rdf:type
> >> ro:Person)]
> >
> >
> > Jena doesn't seem to infer any new nodes.
> Why have both makeSkolem and uriConcat? You either want to create a URI
> resource as your subject or create a bNode. That's trying to make it
> both, which can never happen so the rule never fires.
>
> > I tried separating it into another rule:
> >
> >   [r1: (?x rdf:type ro:RosterEntry), (?x ro:hasSignature ?sig),
> regex(?sig,
> >> '(.*) (.*)', ?first, ?last), makeSkolem(?y, ?x) -> (?y ro:hasFirstName
> >> ?first),  (?y ro:hasLastName ?last),  (?y rdf:type ro:Person)]
> >>   [r2: (?x rdf:type ro:Person), (?x ro:hasFirstName ?first), (?x
> >> ro:hasLastName ?last), uriConcat('http://example.com/ont/roster/people/
> ',
> >> ?first, ?last, ?y) -> print('woot', ?y)]
> >
> >
> > What is strange is that with the second rule, the inference engine prints
> > out:
> >
> > 'woot' <http://example.com/ont/roster/people/BobSmith>
> > 'woot' <http://example.com/ont/roster/people/SallyJones>
> >
> > But, when I listStatements and print out the InfModel,
> >
> > I get the same node URIs:
> >
> > 1PXx9jabIZ6w9mfO0GygJA== type Person .
> >> 1PXx9jabIZ6w9mfO0GygJA== hasLastName "Jones" .
> >> 1PXx9jabIZ6w9mfO0GygJA== hasFirstName "Sally" .
> >> lOqL7Rx2Lwv5OK6BWD/jSA== type Person .
> >> lOqL7Rx2Lwv5OK6BWD/jSA== hasLastName "Smith" .
> >> lOqL7Rx2Lwv5OK6BWD/jSA== hasFirstName "Bob" .
> >
> >
> > So, does uriConcat not set the node's uri permanently?
>
> Ah, I think you might be imaging that uriConcat somehow rewrites the
> node in an RDF graph so it has a name. No. Like all the rule builtins
> all it does is bind a value to a variable or, if the variable already
> has a value, then test it matches.
>
> So just should just need something like (untested):
>
>   [r1: (?x rdf:type ro:RosterEntry),
>        (?x ro:hasSignature ?sig),
>        regex(?sig, '(.*) (.*)', ?first, ?last),
>       uriConcat('http://example.com/ont/roster/people/', ?first, ?last,
> ?y)
>     -> (?y ro:hasFirstName ?first),
>        (?y ro:hasLastName ?last),
>        (?y rdf:type ro:Person)]
>
> Dave
>
> > On Sun, May 24, 2020 at 6:03 AM Dave Reynolds <dave.e.reyno...@gmail.com
> >
> > wrote:
> >
> >> Sorry, only just noticed this question. Responses below:
> >>
> >> On 20/05/2020 10:41, Kenneth Keefe wrote:
> >>> Thanks for all the help so far! I've made some good progress on this
> >>> example I'm trying to forge. Here are the files for this example:
> >>>
> >>> Ontology: https://cioi.iti.illinois.edu/ont/examples/roster.owl
> >>> Rules: https://cioi.iti.illinois.edu/ont/examples/roster.rules
> >>>
> >>> Using this code:
> >>>
> >>> OntModel model =
> >> ModelFactory.*createOntologyModel*(OntModelSpec.*OWL_MEM*);
> >>>
> >>> model.read("file:roster.owl");
> >>>
> >>> List<Rule> rules = Rule.*rulesFromURL*("file:roster.rules");
> >>>
> >>> Reasoner reasoner = new GenericRuleReasoner(rules);
> >>>
> >>> InfModel inf = ModelFactory.*createInfModel*(reasoner, model);
> >>>
> >>>
> >>> printAllStatements(inf);
> >>>
> >>> I get this output (I use the LocalName for the predicates and objects
> for
> >>> readability):
> >>>
> >>> b04230c7-55dc-4e08-92d7-26559c0c478f hasLastName "Smith" .
> >>> c33de24f-82f1-4aa2-a78e-73201341b274 type Person .
> >>> c812ff54-30bf-49e7-8e35-3544dad096b7 hasFirstName "Sally" .
> >>> 16b7a887-2fb9-4bdb-a529-34ca8b3137e4 hasFirstName "Bob" .
> >>> b31eb7d5-a8ad-469e-ae83-366bdf46fd72 hasLastName "Jones" .
> >>> 8b46f0c7-4eb2-41e2-8789-8967e8f63eec type Person .
> >>> http://example.com/ont/roster/ versionIRI .
> >>> http://example.com/ont/roster/ type Ontology .
> >>> http://example.com/ont/roster/RosterEntry type Class .
> >>> http://example.com/ont/roster/bobEntry hasSignature "Bob Smith" .
> >>> http://example.com/ont/roster/bobEntry type RosterEntry .
> >>> http://example.com/ont/roster/bobEntry type NamedIndividual .
> >>> http://example.com/ont/roster/Person type Class .
> >>> http://example.com/ont/roster/hasLastName range string .
> >>> http://example.com/ont/roster/hasLastName domain Person .
> >>> http://example.com/ont/roster/hasLastName type DatatypeProperty .
> >>> http://example.com/ont/roster/sallyEntry hasSignature "Sally Jones" .
> >>> http://example.com/ont/roster/sallyEntry type RosterEntry .
> >>> http://example.com/ont/roster/sallyEntry type NamedIndividual .
> >>> http://example.com/ont/roster/hasSignature range string .
> >>> http://example.com/ont/roster/hasSignature domain RosterEntry .
> >>> http://example.com/ont/roster/hasSignature type DatatypeProperty .
> >>> http://example.com/ont/roster/hasFirstName range string .
> >>> http://example.com/ont/roster/hasFirstName domain Person .
> >>> http://example.com/ont/roster/hasFirstName type DatatypeProperty .
> >>>
> >>> Here are my questions:
> >>>
> >>> Focusing on just the Bob Smith entry:
> >>>
> >>> b04230c7-55dc-4e08-92d7-26559c0c478f hasLastName "Smith" .
> >>> c33de24f-82f1-4aa2-a78e-73201341b274 type Person .
> >>> 16b7a887-2fb9-4bdb-a529-34ca8b3137e4 hasFirstName "Bob" .
> >>>
> >>> 1. Are these unique ids of anonymous nodes?
> >>
> >> Yes.
> >>
> >>> 2. Why are they not identical across these three lines?
> >>
> >> Because your ?y variable hasn't been bound in the rule body, each triple
> >> pattern finds there's no value for ?y and separately treats it as a
> bNode.
> >>
> >> If you want a shared bNode then use makeTemp(?y) in the body (or
> >> makeSoklem).
> >>
> >>> 3. Is there a way to name these new nodes in the rule? For example,
> make
> >>> the new node http://example.com/ont/roster/people/BobSmith.
> >>
> >> Sure, use uriConcat, something like (untested):
> >>
> >>      uriConcat('http://example.com/ont/roster/people/', ?first, ?last,
> >> ?y) -> ...
> >>
> >> Dave
> >>
> >>>
> >>> Thank you!
> >>>
> >>> Ken
> >>>
> >>>
> >>>
> >>>
> >>>
> >>> On Tue, May 12, 2020 at 1:44 AM Lorenz Buehmann <
> >>> buehm...@informatik.uni-leipzig.de> wrote:
> >>>
> >>>> Hi,
> >>>>
> >>>> I think the rule would be basically
> >>>>
> >>>> [r1: (?x rdf:type ex:RosterEntry), (?x ex:hasSignature ?sig),
> >>>> regex(?sig, '(.*) (.*)', ?first, ?last)  -> (?x ex:hasFirstName
> >>>> ?first),  (?x ex:hasLastName ?last),  (?x rdf:type ex:Person) ) ]
> >>>>
> >>>> Note, it's untested and you have to define your prefix ex: in the
> rules
> >>>> file. You might also have to adapt the regex pattern to cover
> different
> >>>> white space chars.
> >>>>
> >>>> On 12.05.20 00:56, Kenneth Keefe wrote:
> >>>>> I am pretty new to using Jena and OWL. I have read many great
> tutorials
> >>>>> regarding RDF and OWL. The focus of those tutorials has largely been
> >> how
> >>>> to
> >>>>> structure the ontology and define restrictions on properties and
> such.
> >>>>> However, I have not been able to find good tutorials that explain how
> >>>>> inference is done and how I can define my own inference rules. I'm
> >>>>> wondering if I am simply not searching for the right thing.
> >>>>>
> >>>>> Regardless, here is a significant example that I think will really
> help
> >>>> me
> >>>>> get started with inference using Jena. I created a minimal example to
> >>>>> enable discussion. Here is a pastebin:
> https://pastebin.com/ScTGcbcZ
> >>>>>
> >>>>> The ontology has two classes, RosterEntry and Person and three data
> >>>>> properties, Signature (associated with RosterEntry), and FirstName
> and
> >>>>> LastName (both associated with Person). The example also has two
> >>>>> RosterEntry individuals with signatures of "Bob Smith" and "Sally
> >> Jones."
> >>>>>
> >>>>> I would like to write a rule that causes Jena to infer the following
> >> new
> >>>>> facts:
> >>>>>
> >>>>> <owl:Individual>
> >>>>>>           <rdf:type
> >>>>>>               rdf:resource="http://example.com/ont/roster/Person";
> />
> >>>>>>           <hasFirstName>Bob</hasFirstName>
> >>>>>           <hasLastName>Smith</hasLastName>
> >>>>>
> >>>>>       </owl:Individual>
> >>>>>
> >>>>>
> >>>>> <owl:Individual>
> >>>>>>           <rdf:type
> >>>>>>               rdf:resource="http://example.com/ont/roster/Person";
> />
> >>>>>>           <hasFirstName>Sally</hasFirstName>
> >>>>>           <hasLastName>Jones</hasLastName>
> >>>>>
> >>>>>       </owl:Individual>
> >>>>>
> >>>>>
> >>>>> How do I do that? Full answers or nudges in the right direction are
> >> both
> >>>>> very welcome. Thank you!
> >>>>>
> >>>>> Ken
> >>>>>
> >>>>
> >>>>
> >>>
> >>
> >
> >
>


-- 
-------
Ken Keefe
Senior Software Engineer
Information Trust Institute
University of Illinois at Urbana-Champaign
1308 W. Main St.
CSL 225
Urbana, Illinois 61801, USA
Phone: 217-244-3203
Web: https://www.perform.illinois.edu/~kjkeefe
Email: kjke...@illinois.edu

Reply via email to