我遇到了一个困难: 我在 owlready2 中创建了一个对象属性(例如:has_parent)并将其定义为另一个对象属性的逆属性(例如:has_child)。当我通过第一个属性将一个人(例如“John”)与另一个人(例如“Kevin”)关联起来以创建“John has_parent Kevin”作为三元组时,预计逆三元组“Kevin has_child John”将在推理过程之后创建。但事实并非如此。当我在推理过程之前查询“通过 has_child 属性将 Kevin 与哪个人联系起来”时,它回答:约翰! 但这并不是问题本身。当我执行推理过程,然后保存推理结果和主本体本身时,问题就出现了:本体中不存在三元组“Kevin has_child John”,推理结果中也不存在!
另一个问题是,当我在 owlready2 中为对象属性定义域和范围,并定义另一个属性作为第一个属性的逆时,预期逆属性的域和范围设置为推理后分别为第一个的值域和定义域。但事实并非如此。并且推理后没有给逆性质设定定义域和值域。
我尝试用另一种方式定义逆属性,但没有成功。
代码如下:
从 owlready2 导入 *
onto = get_ontology(“http://test.org/Family#”)
随着:
'''defining base classes'''
class Human(Thing): pass
class Man(Human): pass
class Woman(Human): pass
AllDisjoint([Man, Woman])
'''defining properties'''
class has_couple(Human>>Human): pass
class has_wife(has_couple, Man>>Woman): pass
class has_husbend(has_couple):
inverse=has_wife
class has_child (Human>>Human): pass
class has_parent (ObjectProperty):
inverse=has_child
'''defining individuals'''
John = Man("John")
Kevin = Man("Kevin")
'''defining relations between individuals'''
John = Man("John", has_parent=[Kevin])
打印(凯文.has_child)
'''推理'''
随着:
sync_reasoner_pellet(infer_property_values=True, infer_data_property_values = True)
打印(has_husbend.domain)
'''节省'''
onto.save(“test.owl”,格式=“rdfxml”)
这个答案只是关于逆性质,而不是关于定义域和范围。
我无法在文档中验证它,但我认为这是
owlready2
的设计决策,实现 owl:inverseOf
的语义,因此在查询中返回额外的三元组,但从 save()
中排除这些额外的三元组功能。
这样做的原因是一般原则,即您不应将原始本体中不存在的(冗余)三元组添加到知识库中。自动添加此类三元组可能会导致文件大小和内存需求大幅增加,这是不必要的,例如,如果存在适用于每个人拥有的属性的逆属性的定义。
此外,逆语义的自动应用可能会导致某些更复杂关系的错误事实,并且您需要人机交互或某种可解释性算法来检查结果是否正确。但是,如果您只是将派生事实输入知识库中,则不再可能区分原始事实和新事实,因此在这种情况下检查结果(甚至知道已添加新事实)不再可能。
总而言之:这是
owlready2
的预期行为。如果您想使用像 Kevin has_child John 这样的派生事实,那么您应该使用 owlready2
本身或实现 owl:inverseOf
的另一个引擎。
但是,如果您确实想要 xml 中的所有三元组,那么您可以使用
rdflib
自行输出它们,方法是循环所有实例,并为每个实例循环所有属性。
代码:
from owlready2 import *
from rdflib import Graph, URIRef, Namespace
from rdflib.namespace import RDF, RDFS, OWL
onto = get_ontology("http://test.org/Family#")
with onto:
'''defining base classes'''
class Human(Thing): pass
class Man(Human): pass
class Woman(Human): pass
AllDisjoint([Man, Woman])
'''defining properties'''
class has_couple(Human>>Human): pass
class has_wife(has_couple, Man>>Woman): pass
class has_husband(has_couple):
inverse=has_wife
class has_child (Human>>Human): pass
class has_parent (ObjectProperty):
inverse=has_child
'''defining individuals'''
Kevin = Man("Kevin")
'''defining relations between individuals'''
John = Man("John", has_parent=[Kevin])
Mary = Woman("Mary", has_husband=[Kevin])
print("Kevin.has_child:", Kevin.has_child)
print("Kevin.has_wife:", Kevin.has_wife)
fam = Namespace("http://test.org/Family#")
graph = Graph(base="http://test.org/Family")
graph.bind('fam', fam)
A = RDF.type
for person in Human.instances():
# add a node for this person
graph.add((URIRef('#'+person.name), A, OWL.NamedIndividual))
# add all rdf:type nodes (usually just 1)
for entity_type in person.is_a:
graph.add((URIRef('#'+person.name), A, URIRef('#'+entity_type.name)))
# add all person-property-object triples
for prop in person.get_properties():
# a property can have multiple values
for value in prop[person]:
graph.add((URIRef('#'+person.name), fam.term(prop.name), URIRef('#'+value.name)))
# print xml, don't nest nodes (max_depth=1)
print(graph.serialize(format="pretty-xml", max_depth=1))
这将打印以下内容:
<?xml version="1.0" encoding="utf-8"?>
<rdf:RDF xml:base="http://test.org/Family"
xmlns:ns1="#"
xmlns:fam="http://test.org/Family#"
xmlns:owl="http://www.w3.org/2002/07/owl#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
>
<owl:NamedIndividual rdf:about="#Mary">
<rdf:type rdf:resource="#Woman"/>
<fam:has_husband rdf:resource="#Kevin"/>
</owl:NamedIndividual>
<owl:NamedIndividual rdf:about="#Kevin">
<rdf:type rdf:resource="#Man"/>
<fam:has_wife rdf:resource="#Mary"/>
<fam:has_child rdf:resource="#John"/>
</owl:NamedIndividual>
<owl:NamedIndividual rdf:about="#John">
<rdf:type rdf:resource="#Man"/>
<fam:has_parent rdf:resource="#Kevin"/>
</owl:NamedIndividual>
</rdf:RDF>
一些注意事项:
has_husband=[Kevin]
添加了一个单独的 Mary 来测试逆 has_husband/has_wife owlready2
本身使用的 xml 语法。我无法修改的唯一区别是 owlready2
使用普通关系 <has_child>
,而 rdflib
使用此代码生成 <fam:has_child>
,名称空间的别名为 fam:
。