Как сделать свойство функционального объекта свойством нефункционального объекта?

У меня возникла проблема, когда я пытаюсь изменить свой файл OWL с помощью API Jena OntModel и т. д. Оригинальный файл 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 в нефункциональное свойство?


person user3194152    schedule 07.05.2014    source источник
comment
Это очень интересный вопрос, и, кажется, он сводится к тому факту, что Jena выполняет кэширование от вашего имени, но, изменяя базовую модель, вы нарушаете некоторые из предположений, что кэширование делает. Я написал это в ответе и предоставил то, что я считаю лучшим обходным путем.   -  person Joshua Taylor    schedule 07.05.2014


Ответы (1)


Укороченная версия

Методы, которые 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(); не работает.

На самом деле вы не предоставили достаточно информации о том, что означает «не работает», но вот пример, который, я думаю, подчеркивает, что вы имели в виду. Удивительно, но первый вызов 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. Так что по какой-то причине он по-прежнему возвращает значение 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? Было бы слишком дорого проводить проверку работоспособности при каждом использовании. Это может быть особенно плохо, если некоторые из необходимых данных были выведены из какого-то другого источника.

Я думаю, что решение здесь заключается в том, что если вы хотите изменить модель, то использование API OntModel более высокого уровня может быть опасным, потому что многое зависит от кэширования, которое вы собираетесь сделать недействительным. Если это так, я думаю, что сделать свойство нефункциональным все же следует, удалив тройку prop rdf:type owl:FunctionalProperty. Просто вместо того, чтобы использовать convertToFunctionalProperty, вы должны просто снова добавить тройку prop rdf:type owl:FunctionalProperty.

person Joshua Taylor    schedule 07.05.2014
comment
Большое спасибо! Оно работает! Спасибо за подробное решение! - person user3194152; 09.05.2014