ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Ontology 不只是画 Class:用 Owlready2 讲透 ObjectProperty、InverseProperty 与 Reasoner 推理

Ontology 不只是画 Class:用 Owlready2 讲透 ObjectProperty、InverseProperty 与 Reasoner 推理 很多程序员第一次接触 Ontology本能反应都是不就是定义几个 Class然后把它们连起来吗比如Person Student Teacher Course School然后画成Person / \ Student Teacher看起来和 UML 类图似乎没什么区别。如果 Ontology 只能做到这里那确实没必要专门学习 OWL。数据库有表结构Java 有 ClassPython 有 classJSON Schema 也能描述数据结构。Ontology 真正有意思的地方不是 Class而是 Property Restriction Reasoner。也就是说Class ObjectProperty InverseProperty TransitiveProperty Restriction Reasoner组合起来以后我们得到的不再是一张“知识结构图”而是一套机器可以进行逻辑推理的知识模型。例如我们只告诉系统张三 是 学生 张三 学习 Python课程 Python课程 由 王老师 教授如果本体中定义好了关系和规则Reasoner 就可能进一步推导出一些没有显式写入的数据。这才是 Ontology 和普通数据库模型最大的区别之一。今天我们不用 Protégé而是直接使用 Python 的 Owlready2从代码角度把这件事情讲透。一、Owlready2 是什么Owlready2 是 Python 生态中非常实用的 OWL Ontology 操作库。如果你以前使用过 Protégé可以简单理解为Protégé ↓ 人通过 GUI 编辑 OWL Owlready2 ↓ Python 程序通过代码创建、查询、修改和推理 OWL也就是说我们可以直接写fromowlready2import*ontoget_ontology(http://example.org/school.owl)然后在 Python 中创建 Classwithonto:classPerson(Thing):passclassStudent(Person):passclassTeacher(Person):pass甚至直接创建实例zhangsanStudent(ZhangSan)最后保存onto.save(fileschool.owl)于是 Python 程序就能直接生成一个标准 OWL 本体文件。对于后端程序员来说这比一上来就在 Protégé 里面拖拖拽拽更容易理解 Ontology 到底是什么。二、先创建一个最简单的学校本体先安装pipinstallowlready2创建fromowlready2import*ontoget_ontology(http://example.org/school.owl)withonto:classPerson(Thing):passclassStudent(Person):passclassTeacher(Person):passclassCourse(Thing):passclassSchool(Thing):pass现在我们的模型是Thing ├── Person │ ├── Student │ └── Teacher │ ├── Course │ └── School这一步其实非常普通。因为数据库同样可以创建CREATETABLEstudent(...);CREATETABLEteacher(...);CREATETABLEcourse(...);真正开始体现 Ontology 特性的地方是下面的 Property。三、ObjectPropertyOntology 的关系不是普通字段假设我们希望表达张三 学习 Python 李老师 教授 Python传统数据库可能设计student course student_course teacher_course而在 OWL 中可以定义 ObjectProperty。例如withonto:classstudies(ObjectProperty):domain[Student]range[Course]这里定义studies它的domain Student range Course也就是Student --studies-- Course创建实例zhangsanonto.Student(ZhangSan)python_courseonto.Course(PythonCourse)zhangsan.studies.append(python_course)于是知识图谱中出现ZhangSan | studies ↓ PythonCourse转换成 RDF Triple就是ZhangSan studies PythonCourse也就是经典的Subject Predicate Object四、ObjectProperty 和数据库外键有什么区别很多数据库开发者看到这里会说这不就是 Foreign Key 吗表面上很像。比如student_course----------------student_id course_id确实可以表达Student → Course但是 OWL Property 不只是存储“谁关联谁”。它本身具有逻辑语义。例如我们可以声明studies inverseOf hasStudent还可以声明partOf 是传递关系甚至可以定义每一个 CSStudent 至少学习一门 ProgrammingCourse这些定义能够被 Reasoner 使用。所以更准确地说数据库 Foreign Key ↓ 数据完整性 / 数据关联 OWL ObjectProperty ↓ 语义关系 / 逻辑推理五、InverseProperty关系可以自动反过来这是 Owlready2 非常适合演示的一个功能。假设我们有Student --studies-- Course那么从 Course 的角度看其实还存在Course --hasStudent-- Student正常数据库里你可能需要SELECTstudent.*FROMstudentJOINstudent_course...但 OWL 可以直接告诉 Reasonerstudies和hasStudent互为反向关系。代码withonto:classstudies(ObjectProperty):domain[Student]range[Course]classhasStudent(ObjectProperty):domain[Course]range[Student]studies.inverse_propertyhasStudent然后zhangsanonto.Student(ZhangSan)python_courseonto.Course(PythonCourse)zhangsan.studies.append(python_course)我们声明的是ZhangSan studies PythonCourse逻辑上对应PythonCourse hasStudent ZhangSan这就是Inverse Object PropertyOWL 表达可以理解为studies ≡ inverse(hasStudent)或者studies(x, y) ↓ hasStudent(y, x)这已经开始脱离普通“画 Class”的范畴了。六、再来一个更现实的例子teaches继续增加withonto:classteaches(ObjectProperty):domain[Teacher]range[Course]classtaughtBy(ObjectProperty):domain[Course]range[Teacher]teaches.inverse_propertytaughtBy创建老师teacher_wangonto.Teacher(TeacherWang)teacher_wang.teaches.append(python_course)现在图谱TeacherWang | teaches ↓ PythonCourse ↑ studies | ZhangSan反向关系PythonCourse taughtBy TeacherWang PythonCourse hasStudent ZhangSan于是围绕 Course我们实际上形成了一个语义网络。这就是为什么 Knowledge Graph 很少只讨论 Entity。真正重要的是Entity Relation七、TransitiveProperty传递关系接下来进入更有意思的部分。假设我们需要描述组织结构AI实验室 partOf 计算机学院 partOf 某某大学那么人类很自然会认为AI实验室 partOf 某某大学但是我们并没有直接写这一条数据。这时候可以定义partOf是 TransitiveProperty。代码withonto:classOrganization(Thing):passclasspartOf(ObjectProperty,TransitiveProperty):domain[Organization]range[Organization]创建实例universityonto.Organization(University)computer_schoolonto.Organization(ComputerSchool)ai_labonto.Organization(AILab)建立关系ai_lab.partOf.append(computer_school)computer_school.partOf.append(university)原始数据只有AILab | partOf ↓ ComputerSchool | partOf ↓ University因为partOf被声明为传递关系所以逻辑上partOf(AILab, ComputerSchool) partOf(ComputerSchool, University)可以推出partOf(AILab, University)写成逻辑形式A partOf B B partOf C ----------- A partOf C这就是传递推理。八、为什么这对知识图谱非常重要因为现实世界中大量关系天然具有这种结构。例如文件 → 属于 → 文件夹 文件夹 → 属于 → 项目 项目 → 属于 → 企业如果belongsTo具有合适的传递语义那么可以推导文件 → belongsTo → 企业类似的还有locatedIn partOf contains ancestorOf但这里一定要注意不是所有关系都能随便声明成 TransitiveProperty。例如张三 likes 李四 李四 likes 王五显然不能推出张三 likes 王五所以likes通常不是传递关系。Ontology 建模最重要的能力之一就是判断一个关系到底具有什么逻辑性质。九、FunctionalProperty一个对象最多对应一个值OWL Property 还可以具有更多特性。例如一个人只有一个出生地withonto:classPlace(Thing):passclassbornIn(ObjectProperty,FunctionalProperty):domain[Person]range[Place]这里FunctionalProperty表示对于一个 Subject这个 Property 最多对应一个 Object。也就是Person → bornIn → Place最多一个。类似hasBirthPlace hasBiologicalMother hasID某些业务场景可以具有 Functional 的语义。十、InverseFunctionalProperty 又是什么反过来InverseFunctionalProperty表达的是一个 Object 最多由一个 Subject 通过这个 Property 指向。比如某些具有唯一性的身份标识关系。假设Person --hasIdentity-- Identity如果hasIdentity被定义为 InverseFunctionalProperty那么两个不同 Person 指向同一个 Identity 时就会产生更强的身份语义。在 OWL 中这种特性和普通数据库 UNIQUE 有一点相似但不能简单地把二者完全等同。因为 OWL 的目标是逻辑语义数据库约束的目标主要是数据完整性两者出发点不同。十一、RestrictionOntology 真正开始“烧脑”的地方接下来就是 OWL 最核心的内容之一Restriction也就是限制条件。比如我们定义Student但什么样的人是 Student最简单classStudent(Person):pass这只是告诉系统Student ⊆ Person也就是说所有 Student 都是 Person但是我们还可以继续定义Student 必须至少学习一门 Course这时候就需要 Restriction。十二、some至少存在一个关系例如classActiveStudent(Student):equivalent_to[Studentstudies.some(Course)]它表达ActiveStudent ≡ Student AND studies SOME Course换成人话一个 Student只要至少 studies 某个 Course就属于 ActiveStudent。逻辑形式Student AND ∃ studies.Course这里∃就是 Existential Restriction。也就是至少存在一个。假设ZhangSan studies PythonCourse并且PythonCourse rdf:type Course那么 Reasoner 就可以进一步判断ZhangSan rdf:type ActiveStudent注意我们并没有手动写zhangsan.is_a.append(ActiveStudent)而是 Reasoner 根据定义推出来的。这就是 Ontology 推理真正有价值的地方。十三、only所有关系对象必须属于某个 Class还有studies.only(Course)对应∀ studies.Course意思是studies 指向的所有对象都属于 Course。例如classNormalStudent(Student):is_a[studies.only(Course)]这里需要特别注意some和only完全不是一个意思。some(Course)表示至少存在一个 studies 对象属于 Course而only(Course)表示所有 studies 对象都必须属于 Course初学 OWL 时这两个概念特别容易混。十四、min / max / exactly数量限制OWL 还可以定义 Cardinality。比如至少学习 1 门课程可以写studies.min(1,Course)最多学习 5 门studies.max(5,Course)正好学习 3 门studies.exactly(3,Course)例如withonto:classFullTimeStudent(Student):equivalent_to[Studentstudies.min(3,Course)]概念上FullTimeStudent ≡ Student AND 至少 studies 3 个 Course这已经远远超过普通 Class Diagram 的表达能力了。十五、Restriction 和数据库 CHECK 有什么区别很多数据库开发者可能又会想到CHECK(...)但二者依然不能简单画等号。数据库约束通常在做这个数据允不允许 INSERT而 OWL Restriction 更重要的用途之一是这个实体在逻辑上属于什么 Class例如Student studies some ProgrammingCourse可以被 Reasoner 推理成ProgrammingStudent它更接近知识分类 逻辑推导而不只是数据校验。十六、定义一个 ProgrammingStudent现在我们做一个更完整的例子。首先定义课程类型withonto:classCourse(Thing):passclassProgrammingCourse(Course):passclassDatabaseCourse(Course):pass然后定义withonto:classProgrammingStudent(Student):equivalent_to[Studentstudies.some(ProgrammingCourse)]创建课程python_courseonto.ProgrammingCourse(PythonCourse)mysql_courseonto.DatabaseCourse(MySQLCourse)创建学生zhangsanonto.Student(ZhangSan)建立关系zhangsan.studies.append(python_course)现在我们显式知道ZhangSan rdf:type Student PythonCourse rdf:type ProgrammingCourse ZhangSan studies PythonCourse但ZhangSan rdf:type ProgrammingStudent没有手动写入。Reasoner 可以根据ProgrammingStudent ≡ Student AND studies SOME ProgrammingCourse推导出来。十七、Reasoner 到底在干什么这是理解 Ontology 最关键的一步。很多人觉得 Reasoner 很神秘。其实可以粗略理解成已有事实 Ontology 定义 逻辑规则 ↓ Description Logic Reasoning ↓ 推导新的逻辑结论例如已有事实ZhangSan type Student PythonCourse type ProgrammingCourse ZhangSan studies PythonCourseOntologyProgrammingStudent ≡ Student AND studies SOME ProgrammingCourseReasonerZhangSan 满足 ProgrammingStudent 的定义因此推出ZhangSan type ProgrammingStudent这就是 Classification / Realization 等推理能力背后的基本思想。十八、用 Owlready2 调用推理机Owlready2 可以调用推理机执行推理。一个典型写法withonto:sync_reasoner()或者根据环境和需要使用 Pelletwithonto:sync_reasoner_pellet(infer_property_valuesTrue
返回列表