OWLにはプロパティの連鎖property chainという表現がある。プロパティを関数とみなすなら、これは関数の合成である。よって合成compositionと呼ばれる。PropertyChain([Property1, Property2, ...])で表される。
>>> from owlready2 import *
>>> onto = get_ontology('http://test.org/test/')
>>> with onto:
... class p01():pass
...
>>> onto.search(iri='*')
[.anonymous, test.org.test]
>>> onto.p01
>>> with onto:
... class A(Thing):pass
... class B(Thing):pass
... class C(Thing):pass
... class p01(A>>B):pass
... class p02(B>>C):pass
... class p(A>>C):pass
...
>>> onto.p.property_chain = PropertyChain([onto.p01, onto.p02])
>>> onto.save('test.rdf')
>>> onto.search(iri='*')
[.anonymous, test.org.test, test.A, test.B, test.C, test.p01, test.p02, test.p]
RDF/XMLでは次のように記述される。
<owl:ObjectProperty rdf:about="p">
<rdfs:domain rdf:resource="A"/>
<rdfs:range rdf:resource="C"/>
<owl:propertyChainAxiom>
<rdf:Description>
<rdf:first rdf:resource="p01"/>
<rdf:rest>
<rdf:Description>
<rdf:first rdf:resource="p02"/>
<rdf:rest rdf:resource="http://www.w3.org/1999/02/22-rdf-syntax-ns#nil"/>
</rdf:Description>
</rdf:rest>
</rdf:Description>
</owl:propertyChainAxiom>
</owl:ObjectProperty>
タートルファイル形式ntriplesも見ておく。
### http://test.org/test/p
<http://test.org/test/p> rdf:type owl:ObjectProperty ;
rdfs:domain <http://test.org/test/A> ;
rdfs:range <http://test.org/test/C> ;
owl:propertyChainAxiom ( <http://test.org/test/p01>
<http://test.org/test/p02>
) .
owl:propertyChainAxiomプロパティでは、2つのプロパティを括弧( )でくくって並べて記述する。
クラス定義の例
それではクラスの例を示す。
>>> from owlready2 import *
>>> onto = get_ontology('bacteria.owl').load()
>>> with onto:
... class Coccus(onto.Bacterium):
... equivalent_to = [
... onto.Bacterium & onto.has_shape.some(onto.Round)
... & onto.has_shape.only(onto.Round)
... ]
...
>>> with onto:
... class Pseudomonas(onto.Bacterium):
... is_a = [
... onto.has_shape.some(onto.Rod),
... onto.has_shape.only(onto.Rod),
... onto.has_grouping.some(onto.Isolated | onto.InPair),
... onto.gram_positive.value(False)
... ]
どちらもクラスの内容を記述しているが、equivalent_toとis_aというプロパティを用いている。
RDF/XMLで確認する。
<owl:Class rdf:about="#Coccus">
<rdfs:subClassOf rdf:resource="#Bacterium"/>
<owl:equivalentClass>
<owl:Class>
<owl:intersectionOf rdf:parseType="Collection">
<rdf:Description rdf:about="#Bacterium"/>
<owl:Restriction>
<owl:onProperty rdf:resource="#has_shape"/>
<owl:someValuesFrom rdf:resource="#Round"/>
</owl:Restriction>
<owl:Restriction>
<owl:onProperty rdf:resource="#has_shape"/>
<owl:allValuesFrom rdf:resource="#Round"/>
</owl:Restriction>
</owl:intersectionOf>
</owl:Class>
</owl:equivalentClass>
</owl:Class>
<owl:Class rdf:about="#Pseudomonas">
<rdfs:subClassOf rdf:resource="#Bacterium"/>
<rdfs:subClassOf>
<owl:Restriction>
<owl:onProperty rdf:resource="#has_shape"/>
<owl:someValuesFrom rdf:resource="#Rod"/>
</owl:Restriction>
</rdfs:subClassOf>
<rdfs:subClassOf>
<owl:Restriction>
<owl:onProperty rdf:resource="#has_shape"/>
<owl:allValuesFrom rdf:resource="#Rod"/>
</owl:Restriction>
</rdfs:subClassOf>
<rdfs:subClassOf>
<owl:Restriction>
<owl:onProperty rdf:resource="#has_grouping"/>
<owl:someValuesFrom>
<owl:Class>
<owl:unionOf rdf:parseType="Collection">
<rdf:Description rdf:about="#Isolated"/>
<rdf:Description rdf:about="#InPair"/>
</owl:unionOf>
</owl:Class>
</owl:someValuesFrom>
</owl:Restriction>
</rdfs:subClassOf>
<rdfs:subClassOf>
<owl:Restriction>
<owl:onProperty rdf:resource="#gram_positive"/>
<owl:hasValue rdf:datatype="http://www.w3.org/2001/XMLSchema#boolean">false</owl:hasValue>
</owl:Restriction>
</rdfs:subClassOf>
</owl:Class>
Coccusはowl:equivalentClassとして記述されることである。これは主語となるCoccusはowl:equivalentClassで記述されるクラスと同等のクラスであるという必要十分条件として記述される。
Pseudomonasはいくつものrdfs:subClasssOfが並んでおり、必要条件を並べてそのすべての構成として定義されるということである。サブクラスなので、それぞれのクラスを継承しているという扱いでもある。
それぞれ、プロパティで内容にアクセスできる。
>>> Coccus.equivalent_to
[bacteria.Bacterium & bacteria.has_shape.some(bacteria.Round) & bacteria.has_shape.only(bacteria.Round), bacteria.Bacterium & bacteria.has_shape.some(bacteria.Round) & bacteria.has_shape.only(bacteria.Round)]
要素の内容が二重になっている。INDIRECT_を付けて、推移性も含めた間接的な関係も入れると(整理すると)、重複はなくなる。
>>> Coccus.INDIRECT_equivalent_to
[bacteria.Bacterium & bacteria.has_shape.some(bacteria.Round) & bacteria.has_shape.only(bacteria.Round)]
>>> Pseudomonas.is_a
[bacteria.Bacterium, bacteria.has_shape.some(bacteria.Rod), bacteria.has_shape.only(bacteria.Rod), bacteria.has_grouping.some(bacteria.Isolated | bacteria.InPair), bacteria.gram_positive.value(False)]