Ho to achieve Mapping between namespaces in Apache Jena thru Reasoning?

删除回忆录丶 提交于 2020-01-04 11:12:48

问题


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();


    }



}

回答1:


You can't just do ns:?x and expect it to match URI resource whose string form begins with whatever ns: 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 that m:Person is used as type, and that x:a a n:Person is in the data, and that m:Person and n:Person have the same suffix with prefixes n: and m:, and infers that x:a a m:Person as a result.

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;

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.reasoner.Reasoner;
import com.hp.hpl.jena.reasoner.rulesys.GenericRuleReasoner;
import com.hp.hpl.jena.reasoner.rulesys.Rule;
import com.hp.hpl.jena.util.PrintUtil;

public class TypeMappingExample {
    public static void main(String[] args) throws IOException {
        PrintUtil.registerPrefix( "n", "urn:ex:n/" );
        PrintUtil.registerPrefix( "m", "urn:ex:m/" );
        String content = "\n" +
                "@prefix n: <urn:ex:n/>.\n" +
                "@prefix m: <urn:ex:m/>.\n" +
                "@prefix x: <urn:ex:x/>" +
                "\n" +
                "x:a a n:Person.\n" +
                "x:b a m:Person.\n" +
                "";
        Model model = ModelFactory.createDefaultModel();
        try ( InputStream in = new ByteArrayInputStream( content.getBytes() )) {
            model.read( in, null, "TTL" );
        }
        String rule = "\n" +
                "[strConcat(n:,'(.*)',?nprefix),\n" +
                " strConcat(m:,'(.*)',?mprefix),\n" +
                " (?x rdf:type ?ntype), strConcat(?ntype,?ntypestr),\n" +
                " (?y rdf:type ?mtype), strConcat(?mtype,?mtypestr)," +
                " regex(?ntypestr,?nprefix,?nsuffix),\n" +
                " regex(?mtypestr,?mprefix,?msuffix),\n" +
                " equal(?nsuffix,?msuffix)\n" +
                " -> \n" +
                "(?x rdf:type ?mtype)]";
        Reasoner reasoner = new GenericRuleReasoner( Rule.parseRules( rule ));
        InfModel imodel = ModelFactory.createInfModel( reasoner, model );
        imodel.write( System.out, "TTL" );
    }
}
@prefix n:     <urn:ex:n/> .
@prefix m:     <urn:ex:m/> .
@prefix x:     <urn:ex:x/> .

x:a     a       m:Person , n:Person .

x:b     a       m:Person .

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:

[(?c1 a rdfs:Class) (?c1 rdfs:isDefinedBy ?ont1) (?c1 rdfs:label ?name)
 (?c2 a rdfs:Class) (?c2 rdfs:isDefinedBy ?ont2) (?c2 rdfs:label ?name)
 ->
 [(?x rdf:type ?c1) -> (?x rdf:type ?c2)]]


来源:https://stackoverflow.com/questions/24806215/ho-to-achieve-mapping-between-namespaces-in-apache-jena-thru-reasoning

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!