Goal:
I wan´t to achieve a rule based Mapping between ontologies in order to fulfill a common task of data migration.
Way to achieve the goal:
To achieve this i developed a abstract data structure which is capable to store all information provided by the xml representation of any datatype. Then i wrote a parser, which constructs a ontology out of targeted document-type definition. Now when i read the data in it is first associated to the abstractDatatype namespace, lets call it aS. The targeted data structure lies in the namespace tS.
Problem:
If i try to express type equity between two Resources with same name but different namespace via a rule like that:
[mappingRule1: (aS:?a rdf:type aS:?b) (tS:?c rdf:type tS:?b) -> (aS:?a rdf:type tS:?b)]
the reasoner does not get it. Maybe there is a mistake in the rule, which should be interpreted as: if there is the same typename mapped to the different namespace tS as it is in aS, all individuals of aS get also the same type in tS The other problem is that this kind of rule might not work if there are no individuals of a type and i´ve been told that expressing it like that might not be sufficient. Nearly alternatively i could also create SubClassOf rules which do the mapping between all combinations, but that would produce a lot of dirt in the model and i would like to be able to add even more filtering conditions instead of making more general.
However if, someone has some experience with rule based ontology mapping, i will be very glad to get some insights.
Here is a java unit test that demonstrates the not working mapping problem:
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.io.BufferedOutputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.junit.Before;
import org.junit.Test;
import com.hp.hpl.jena.rdf.model.InfModel;
import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.rdf.model.ModelFactory;
import com.hp.hpl.jena.rdf.model.Property;
import com.hp.hpl.jena.rdf.model.RDFNode;
import com.hp.hpl.jena.rdf.model.Resource;
import com.hp.hpl.jena.rdf.model.Statement;
import com.hp.hpl.jena.rdf.model.StmtIterator;
import com.hp.hpl.jena.reasoner.Derivation;
import com.hp.hpl.jena.reasoner.Reasoner;
import com.hp.hpl.jena.reasoner.ReasonerRegistry;
import com.hp.hpl.jena.reasoner.rulesys.GenericRuleReasoner;
import com.hp.hpl.jena.reasoner.rulesys.Rule;
import com.hp.hpl.jena.util.PrintUtil;
import com.hp.hpl.jena.vocabulary.RDF;
import com.hp.hpl.jena.vocabulary.RDFS;
public class ReasonerTest {
String aS = "http://www.custom.eu/abstractDatascheme#";
String tS = "http://www.custom.eu/targetDatascheme#";
Model model = ModelFactory.createDefaultModel();
InfModel inf;
Resource AA = model.createResource(aS + "A");
Resource AB = model.createResource(aS + "B");
Resource AC = model.createResource(aS + "C");
Resource AD = model.createResource(aS + "D");
Resource TA = model.createResource(tS + "A");
Resource TB = model.createResource(tS + "B");
Property p = model.createProperty(aS, "p");
Property q = model.createProperty(aS, "q");
@Before
public void init() {
PrintUtil.registerPrefix("aS", aS);
PrintUtil.registerPrefix("tS", tS);
AA.addProperty(p, "foo");
// Get an RDFS reasoner
GenericRuleReasoner rdfsReasoner = (GenericRuleReasoner) ReasonerRegistry.getRDFSReasoner();
// Steal its rules, and add one of our own, and create a reasoner with these rules
List<Rule> rdfRules = new ArrayList<>( rdfsReasoner.getRules() );
List<Rule> rules = new ArrayList<>();
String customRules = "[transitiveRule: (?a aS:p ?b) (?b aS:p ?c) -> (?a aS:p ?c)] \n" +
"[mappingRule1: (aS:?a rdf:type aS:?b) (tS:?c rdf:type tS:?b) -> (aS:?a rdf:type tS:?b)] \n" +
"[mappingRule2a: -> (aS:?a rdfs:subClassOf tS:?a)] \n" +
"[mappingRule2b: -> (tS:?a rdfs:subClassOf aS:?a)]";
rules.addAll(rdfRules);
rules.add(Rule.parseRule(customRules));
Reasoner reasoner = new GenericRuleReasoner(rules);
reasoner.setDerivationLogging(true);
inf = ModelFactory.createInfModel(reasoner, model);
}
@Test
public void mapping() {
AA.addProperty(RDF.type, model.createResource(aS + "CommonType"));
TA.addProperty(RDF.type, model.createResource(tS + "CommonType"));
String trace = null;
trace = getDerivations(trace, AA, RDF.type, TA);
assertNotNull(trace);
}
private String getDerivations(String trace, Resource subject, Property predicate, Resource object) {
PrintWriter out = new PrintWriter(System.out);
for (StmtIterator i = inf.listStatements(subject, predicate, object); i.hasNext(); ) {
Statement s = i.nextStatement();
System.out.println("Statement is " + s);
for (Iterator<Derivation> id = inf.getDerivation(s); id.hasNext(); ) {
Derivation deriv = (Derivation) id.next();
deriv.printTrace(out, true);
trace += deriv.toString();
}
}
out.flush();
return trace;
}
@Test
public void subProperty() {
// Hierarchy
model.add(p, RDFS.subPropertyOf, q);
StmtIterator stmts = inf.listStatements(AA, q, (RDFNode) null);
assertTrue(stmts.hasNext());
while (stmts.hasNext()) {
System.out.println("Statement: " + stmts.next());
}
}
@Test
public void derivation() {
// Derivations
AA.addProperty(p, AB);
AB.addProperty(p, AC);
AC.addProperty(p, AD);
String trace = null;
trace = getDerivations(trace, AA, p, AD);
assertNotNull(trace);
}
@Test
public void derivations() {
String trace = null;
PrintWriter out = new PrintWriter(System.out);
for (StmtIterator i = inf.listStatements(); i.hasNext(); ) {
Statement s = i.nextStatement();
System.out.println("Statement is " + s);
for (Iterator<Derivation> id = inf.getDerivation(s); id.hasNext(); ) {
Derivation deriv = (Derivation) id.next();
deriv.printTrace(out, true);
trace += deriv.toString();
}
}
out.flush();
assertNotNull(trace);
}
@Test
public void listStatements() {
StmtIterator stmtIterator = inf.listStatements();
while (stmtIterator.hasNext()) {
System.out.println(stmtIterator.nextStatement());
}
}
@Test
public void listRules() {
List<Rule> rules = ((GenericRuleReasoner) inf.getReasoner()).getRules();
for (Rule rule : rules) {
System.out.println(rule.toString());
}
}
@Test
public void saveDerivation() {
DataOutputStream out1;
try {
out1 = new DataOutputStream(new BufferedOutputStream(new FileOutputStream("target/test-output/testOnto.owl")));
inf.write(out1);
}
catch (IOException ex) {
Logger.getLogger(ReasonerTest.class.getName()).log(Level.SEVERE, null, ex);
}
}
@Test
public void printRdfRules() {
GenericRuleReasoner rdfsReasoner = (GenericRuleReasoner) ReasonerRegistry.getRDFSReasoner();
List<Rule> customRules = new ArrayList<>(rdfsReasoner.getRules());
PrintWriter writer = null;
try {
File directory = new File("target/test-output/");
if (!directory.exists()) {
directory.mkdir();
}
writer = new PrintWriter("target/test-output/rfd.rules", "UTF-8");
}
catch (IOException ex) {
Logger.getLogger(ReasonerTest.class.getName()).log(Level.SEVERE, null, ex);
}
for (Rule customRule : customRules) {
writer.println(customRule.toString());
}
writer.close();
}
}
You can't just do
ns:?x
and expect it to match URI resource whose string form begins with whateverns:
stand for, and to bind?x
to the remainder (or to the whole thing). If you want to use a rule that looks at the string forms of URIs, you'll have to get their string form with strConcat, and do some matching and extraction with regex. Here's an example that sees thatm:Person
is used as type, and thatx:a a n:Person
is in the data, and thatm:Person
andn:Person
have the same suffix with prefixesn:
andm:
, and infers thatx:a a m:Person
as a result.As you can see, the string processing is rather rough; Jena's builtins are really designed for getting strings from URIs, etc. Some of the SPARQL functions would make this a bit easier, but it'll still be a bit inelegant, because IRIs are really supposed to be opaque identifiers.
A much easier solution would be to make sure that all the classes have labels, and say that two classes have the same label, then instances of one are instances of the other. If you've made good use of rdfs:isDefinedBy, you can make this very slick, with something like: