如何使功能对象属性成为非功能对象属性?

时间:2014-05-07 01:46:42

标签: rdf jena owl ontology

当我尝试使用Jena的OntModel等API修改我的OWL文件时,我遇到了问题。原始的OWL文件是:

<owl:Class rdf:about="file:///c:/onto_for_code_test/test.owl#DevelopmentProject" /> 
<owl:ObjectProperty rdf:about="file:///c:/onto_for_code_test/test.owl#carriesOut" />
<owl:FunctionalProperty rdf:about="hasProgramme">
    <rdf:type rdf:resource="http://www.w3.org/2002/07/owl#ObjectProperty" />
</owl:FunctionalProperty>

我想将功能对象属性更改为非功能对象属性,但我无法找到有关此功能的任何API。所需的OWL文件是:

<owl:Class rdf:about="file:///c:/onto_for_code_test/test.owl#DevelopmentProject" />
<owl:ObjectProperty rdf:about="file:///c:/onto_for_code_test/test.owl#carriesOut" />
<owl:ObjectProperty rdf:about="hasProgramme" />

以下代码为我提供了我想要的OWL:

OntModel otm = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM);
otm.read(DIRECTORY, null);
ObjectProperty hasProgramme = otm.getProperty(NS + "hasProgramme");
hasProgramme.removeProperty(RDF.type, OWL.FunctionalProperty);` 

但是,当我想再次将hasProgramme转换为功能属性时, 使用hasProgramme.convertToFunctionalProperty();不会将hasProgramme rdf:type owl:FunctionalProperty添加回模型!因此,我认为在这种情况下使用hasProgramme.removeProperty(RDF.type, OWL.FunctionalProperty);必须是不正确的。将功能ObjectProperty转换为非功能属性的正确方法是什么?

1 个答案:

答案 0 :(得分:3)

短版

Jena用于实现convertToFunctionalProperty(以及其他多态行为)的方法使用了大量缓存。通过更改基础模型,您违反了缓存所做的一些假设。看起来使属性不起作用的正确方法是

p.removeProperty( RDF.type, OWL.FunctionalProperty );

你已经完成了。要使其再次起作用,请再次添加类型:

p.addProperty( RDF.type, OWL.FunctionalProperty );

长版

使事情失效

我做了一个快速搜索,并没有找到任何将功能属性变成不属于功能属性的东西。我认为您的方法是正确的:删除prop a owl:FunctionalProperty看起来是正确的方法。

使功能正常

OntProperty界面中有许多方法用于在其他类型的属性中转换属性,但不能使它们某些类型的属性。特别是,convertToFunctional方法表示它将:

  

回答此属性的一个方面作为功能属性   如有必要,可为模型提供其他信息。

     

返回:此属性,但转换为FunctionalProperty构面

然而,你成功地使成为一个功能属性,看起来convertToFunctional 应该再次使其正常工作。然而,你说那个

  

但是,当我想将hasProgramme再次转换为功能时,   hasProgramme.convertToFunctionalProperty();不起作用。

你并没有提供足够的信息,说明什么&#34;不起作用&#34;意味着那里,但这里有一个例子,我想,你的意思是什么。令人惊讶的是,第一次拨打convertToFunctionalProperty会添加hasProgram rdf:type owl:FunctionalProperty三联,但如果您手动将其删除,则第二次通话不会再将其添加回来!

import org.apache.jena.riot.Lang;
import org.apache.jena.riot.RDFDataMgr;

import com.hp.hpl.jena.ontology.ObjectProperty;
import com.hp.hpl.jena.ontology.OntModel;
import com.hp.hpl.jena.ontology.OntModelSpec;
import com.hp.hpl.jena.rdf.model.ModelFactory;
import com.hp.hpl.jena.vocabulary.OWL;
import com.hp.hpl.jena.vocabulary.RDF;

public class FunctionalPropertyExample {
    public static void main(String[] args) {
        String ns = "http://stackoverflow.com/q/23507335/1281433/";
        OntModel model = ModelFactory.createOntologyModel( OntModelSpec.OWL_DL_MEM );

        ObjectProperty opHasProgram = model.createOntProperty( ns+"hasProgram" ).convertToObjectProperty();
        System.out.println( "<!-- Model with plain ObjectProperty-->" );
        RDFDataMgr.write( System.out, model, Lang.RDFXML );

        opHasProgram.convertToFunctionalProperty();
        System.out.println( "\n<!-- Model with FunctionalProperty-->" );
        RDFDataMgr.write( System.out, model, Lang.RDFXML );

        opHasProgram.removeProperty( RDF.type, OWL.FunctionalProperty );
        System.out.println( "\n<!-- Model with ObjectProperty again-->" );
        RDFDataMgr.write( System.out, model, Lang.RDFXML );

        opHasProgram.convertToFunctionalProperty();
        System.out.println( "\n<!-- Model with FunctionalProperty again -->" );
        RDFDataMgr.write( System.out, model, Lang.RDFXML );
    }
}
<!-- Model with plain ObjectProperty-->
<rdf:RDF
    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
    xmlns:owl="http://www.w3.org/2002/07/owl#"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema#"
    xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#">
  <owl:ObjectProperty rdf:about="http://stackoverflow.com/q/23507335/1281433/hasProgram">
    <rdf:type rdf:resource="http://www.w3.org/1999/02/22-rdf-syntax-ns#Property"/>
  </owl:ObjectProperty>
</rdf:RDF>

<!-- Model with FunctionalProperty-->
<rdf:RDF
    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
    xmlns:owl="http://www.w3.org/2002/07/owl#"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema#"
    xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#">
  <owl:FunctionalProperty rdf:about="http://stackoverflow.com/q/23507335/1281433/hasProgram">
    <rdf:type rdf:resource="http://www.w3.org/2002/07/owl#ObjectProperty"/>
    <rdf:type rdf:resource="http://www.w3.org/1999/02/22-rdf-syntax-ns#Property"/>
  </owl:FunctionalProperty>
</rdf:RDF>

<!-- Model with ObjectProperty again-->
<rdf:RDF
    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
    xmlns:owl="http://www.w3.org/2002/07/owl#"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema#"
    xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#">
  <owl:ObjectProperty rdf:about="http://stackoverflow.com/q/23507335/1281433/hasProgram">
    <rdf:type rdf:resource="http://www.w3.org/1999/02/22-rdf-syntax-ns#Property"/>
  </owl:ObjectProperty>
</rdf:RDF>

<!-- Model with FunctionalProperty again -->
<rdf:RDF
    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
    xmlns:owl="http://www.w3.org/2002/07/owl#"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema#"
    xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#">
  <owl:ObjectProperty rdf:about="http://stackoverflow.com/q/23507335/1281433/hasProgram">
    <!-- *** there should be an rdf:type owl:FunctionalProperty assertion here! *** -->
    <rdf:type rdf:resource="http://www.w3.org/1999/02/22-rdf-syntax-ns#Property"/>
  </owl:ObjectProperty>
</rdf:RDF>

这很奇怪。为了弄清楚发生了什么,我们需要看一下实现,但我认为答案归结为缓存。 OntPropertyImpl实现了convertToFunctionalProperty(我们将跟随链):

public FunctionalProperty convertToFunctionalProperty() {
    return convertToType( getProfile().FUNCTIONAL_PROPERTY(), "FUNCTIONAL_PROPERTY", FunctionalProperty.class );
}

然后,在OntResourceImpl:

protected <T extends RDFNode> T convertToType( Resource type, String name, Class<T> cls ) {
    checkProfile( type, name );
    if (canAs( cls )) {
        // don't need to update the model, we already can do the given facet
        return as( cls );
    }

    // we're told that adding this rdf:type will make the as() possible - let's see
    addProperty( RDF.type, type );
    return as( cls );
}

因此,如果 canAs( FunctionalProperty.class )返回false,我们会看到该属性将被添加。所以出于某种原因,即使在我们删除了指示该属性是FunctionalProperty的三元组之后,它仍然返回true。在EnhNode:

public <X extends RDFNode> boolean canAs( Class<X> t )
    { return canSupport( t ); }

// ...

protected <X extends RDFNode> boolean canSupport( Class<X> t )
{
    if (alreadyHasView( t )) return true;
    if (getGraph() == null) return false;
    Implementation imp = getPersonality().getImplementation( t );
    return imp == null ? false : imp.canWrap( asNode(), getGraph() );
}

现在,我们无法确定,但alreadyHasView( t )在这里看起来很可疑。毕竟, 已经有了一个FunctionalProperty视图。现在,在多态:

protected <X extends T> boolean alreadyHasView( Class<X> t )
    { return findExistingView( t ) != null; }

/**
    find an existing view in the ring which is an instance of _t_ and
    return it; otherwise return null. If _this_ is an instance, the
    search takes care to find it first.
*/
private <X extends T> X findExistingView( Class<X> t )
    {
    Polymorphic<T> r = this;
    for (;;)
        {
        if (t.isInstance( r ) && r.isValid()) return t.cast( r );
        r = r.ring;
        if (r == this) return null;
        }
    }

我们没有足够的背景知道为什么 findExistingView正在返回非null。为此,我们需要查看addView,它首先添加了它。实施并不是真正重要的部分;问题是这些视图正在缓存,并且canAs不会重构到模型中,以便查看模型中是否仍存在必要的数据。

大多数时候,这可能是有道理的。毕竟,如果你能够转换过去的东西,你仍然可以引用这些对象。如果修改基础模型,那么这些对象现在代表什么?如果您尝试使用它们会发生什么?它们依赖于正常运行的一些数据可能不再存在于数据中。例如,如果您有一个OntClass并删除c rdf:type owl:Class三元组,那么当您尝试使用c时会发生什么?在每次使用时进行健全性检查都太昂贵了。如果从某些其他来源推断某些必要的数据,这可能特别坏。

我认为这里的解决方案是,如果你想修改模型,那么使用更高级别的OntModel API可能是危险的,因为它的大部分依赖于缓存,你将会失效。如果是这种情况,我认为仍然可以通过删除三元组prop rdf:type owl:FunctionalProperty来使一个属性不起作用。它只是而不是使用convertToFunctionalProperty,您应该再次添加三联prop rdf:type owl:FunctionalProperty