Укороченная версия
Методы, которые 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