【问题标题】:Ho to achieve Mapping between namespaces in Apache Jena thru Reasoning?如何通过推理在 Apache Jena 中实现名称空间之间的映射?
【发布时间】:2014-07-17 14:24:28
【问题描述】:

目标:

我不想在本体之间实现基于规则的映射,以完成数据迁移的常见任务。

实现目标的方法:

为了实现这一点,我开发了一种抽象数据结构,它能够存储任何数据类型的 xml 表示提供的所有信息。然后我编写了一个解析器,它从目标文档类型定义中构建了一个本体。现在,当我读取其中的数据时,它首先与 abstractDatatype 命名空间相关联,我们称之为 aS目标数据结构位于命名空间tS中。

问题:

如果我尝试通过这样的规则来表达两个具有相同名称但名称空间不同的资源之间的类型平等:

[mappingRule1: (aS:?a rdf:type aS:?b) (tS:?c rdf:type tS:?b) -> (aS:?a rdf:type tS:?b)]

推理者不明白。可能规则有错误,应该解释为:如果有相同的类型名映射到不同的命名空间 tS,就像在 aS 中一样,那么所有 aS 的个体也会得到tS 中的相同类型 另一个问题是,如果没有某种类型的个体,这种规则可能不起作用,而且我被告知这样表达可能还不够。几乎或者,我也可以创建在所有组合之间进行映射的 SubClassOf 规则,但这会在模型中产生很多 dirt 并且我希望能够添加更多过滤条件而不是制作更一般。

但是,如果有人对基于规则的本体映射有一些经验,我将很高兴获得一些见解。

这是一个演示不工作映射问题的 java 单元测试:

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


    }



}

【问题讨论】:

    标签: java mapping jena reasoning jena-rules


    【解决方案1】:

    您不能只做ns:?x 并期望它匹配字符串形式以ns: 代表的任何开头的URI 资源,并将?x 绑定到其余部分(或整个事物)。如果您想使用查看 URI 的字符串形式的规则,您必须使用 strConcat 获取它们的字符串形式,并使用正则表达式进行一些匹配和提取。这是一个示例,它看到m:Person 用作类型,x:a a n:Person 在数据中,m:Personn:Person 具有相同的后缀,前缀为n:m:,并推断出x:a a m:Person 结果。

    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 .
    

    如您所见,字符串处理比较粗糙; Jena 的内置函数实际上是为从 URI 等获取字符串而设计的。一些 SPARQL 函数会使这变得更容易一些,但它仍然会有点不优雅,因为 IRI 确实应该是不透明标识符。

    一个更简单的解决方案是确保所有类都有标签,并假设两个类具有相同的标签,然后一个类的实例是另一个类的实例。如果你充分利用了 rdfs:isDefinedBy,你可以让它变得非常流畅,比如:

    [(?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)]]
    

    【讨论】:

    • 您的回答再次带来了很多见解。当然,您的建议是解决问题的有效方法,因为 im dealing with a limited space of class definitions in the domain model, i could also write one rule per class like: [CMArticle: (?a rdf:type aS:CommonType) -> (?a rdf:type tS:CommonType)]` 这确实有效。当然,您的想法开启了另一套合适的可能性,我要感谢您。我也认为这个问题是封闭的,因为它看起来规则中的命名空间只是一种说明符,而不是减少变量空间的东西。
    • 好吧,我不会说这是最简单的方法。这只是我想出的第一个。您可以执行类似于第二种方法的操作,并检测相应的类一次以插入每个类的映射规则。不过,一般来说,如果您找到一种不依赖于检查 URI 中字符的方法,这可能是最简单的。
    猜你喜欢
    • 1970-01-01
    • 2021-08-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-13
    相关资源
    最近更新 更多