本体,OWL,Sparql:建模 "something is not there" 和性能考虑
Ontologies, OWL, Sparql: Modelling that "something is not there" and performance considerations
我们想要建模 "something is not there" 而不是缺失信息,例如"a patient did not get chemotherapy" 或 "a patient does not have dyspnea" 的明确陈述不同于关于患者是否有呼吸困难的缺失信息。
我们考虑了几种方法,例如
- 使用否定 class:"No_Dyspnea"。但这在语义上似乎有问题,因为 class 是什么类型?它不能是 "Dyspnea" class.
的后代
- 使用 "not there" 对象属性,例如"denies" 或 "does_not_have" 然后呼吸困难根 class 的个体作为该三元组的对象。
使用空白节点描述个体属于没有呼吸困难的事物组。例如:
dat:PatientW2 a [ rdf:type owl:Class;
owl:complementOf [
rdf:type owl:Restriction ;
owl:onProperty roo:has_finding;
owl:someValuesFrom nci:Dyspnea;
]
] .
我们觉得第三个选项是最 "ontologically correct" 的表达方式。然而,在使用它的过程中,我们在简单的场景中遇到了严重的性能问题。
我们将 Sesame 与 OWLIM-Lite 商店一起使用,并将 NCI 同义词库(280MB,大约 80,000 个概念)和另一个非常小的 ontology 导入商店并添加了两个人,其中一个拥有 complementOf/restriction class.
以下查询一直执行,我在 15 分钟后终止了它:
select *
where {
?s a [ rdf:type owl:Class;
owl:complementOf [
rdf:type owl:Restriction ;
owl:onProperty roo:has_finding;
owl:someValuesFrom nci:Dyspnea;
]
] .
} Limit 100
有人知道为什么吗?我会假设这种方法会创建很多空白节点,并且查询引擎必须遍历整个 NCI 词库并将所有空白节点与这个节点进行比较?
如果我将这个三元组放在一个单独的图中并且只查询该图,查询 returns 即时结果。
总结一下。两个基本问题是:
- 第三种方法真的最适合建模吗"something is not there"
- 这会影响查询性能吗?
编辑 1
我们讨论了提议的选项。它实际上帮助我们阐明了我们真正想要实现的目标:
我们希望能够在特定时间点声明 "Patient has Dyspnea" 或 "Patient does not have Dyspnea"。
将来 may/will 会有关于该患者的更多信息,例如he/she 现在有呼吸困难。
我们希望能够编写要求 "all patients that have dyspnea" 和 "all patients that do not have dyspnea" 的 Sparql 查询。
我们希望 Sparql 尽可能简单直观。例如。只使用一个 属性 "has_finding" 而不必知道两个属性(一个用于 "has_exclusion")。或者必须了解一些复杂的空白节点构造。
我们试过选项:
- 否定属性断言:这听起来像是解决这个问题的最佳方案,因为我们声明一个人与另一个人没有关系属性.问题是我们必须创造一个呼吸困难的人才能拥有
owl:targetIndividual
之类的东西。除了遍历整个 owl:sourceIndividual
和 owl:targetIndividual
链之外,我们无法找到一种轻松查询否定断言的方法。这使得 Sparql 相当冗长,并给编写查询的人增加了了解它的负担。
带有 complementOf 的空白节点:我们会用它来说明一些我们不想说明的内容。这将说明 "Patient1 can never have a finding of dyspnea"。而我们要声明 "Patient1 does not have a dyspnea finding now (or at date X)"。所以我们不应该使用这种方法。
使用 Exclusion/Inclusion 类型(选项 1 和 2):仔细查看 Jeen 的建议后,我们认为使用一般 :Exclusion
和 :Inclusion
class 只有一个 属性 has_finding
并且给呼吸困难的人 inclusion/exclusion 类型是最容易理解、查询和提供足够的推理能力。示例:
:Patient1 a :Patient .
:Dyspnea1 a :Dyspnea .
:Dyspnea1 a :Exclusion.
:Patient1 ex:has_finding :Dyspnea1 .
这样,编写 Sparql 查询的人只需知道:
- 有一个属性
has_finding
,恰到好处地表达了用意。由于 "No dyspnea" 在技术上也是一个发现。
- 但是仅使用
has_finding
进行查询并不能提供有关此人是否实际拥有它的足够信息。查询还需要包含关于呼吸困难个体是否 a :Exclusion
(或包含取决于查询目标)的三元组。
- 虽然这给查询编写者带来了一些额外的负担,但它比否定 属性 断言要少并且更容易理解。
我们非常感谢对这些结论的一些反馈!
关于建模问题,我想提供第四种选择,实际上是您的选项 1 和 2 的混合:为这些引入单独的 class(层次结构) 'excluded/missing' 症状、疾病或治疗,并有特定的排除作为实例:
:Exclusion a owl:Class .
:ExcludedSymptom rdfs:subClassOf :Exclusion .
:ExcludedTreatment rdfs:subClassOf :Exclusion .
:excludedDyspnea a :ExcludedSymptom .
:excludedChemo a :ExcludedTreatment .
:Patient a owl:Class ;
owl:equivalentClass [ a owl:Restriction ;
owl:onProperty :excluded ;
owl:allValuesFrom :Exclusion ] .
// john is a patient without Dyspnea
:john a :Patient ;
:excluded :excludedDyspnea .
可选地,您可以 link 语义排除实例 treatment/symptom/diseases:
:excludedDyspnea :ofSymptom :Dyspnea .
在我看来,这与您的其他选择一样 "ontologically correct"(老实说,这种事情非常主观),并且可能更容易维护、查询和推理。
至于你的第二个问题:虽然我不能代表你正在使用的特定推理器的行为,但一般来说,任何涉及 complementOf
的构造在计算上都非常繁重,但也许更重要的是,它可能无法捕捉到您的意图。
OWL 有一个开放世界假设,这(从广义上讲)意味着我们不能仅仅因为某个事实目前未知就断定某个事实是不真实的。您的 complementOf
构造在逻辑上将是空的 class,因为对于任何人 X
,即使我们目前不知道 X
已被诊断出患有呼吸困难,也存在将来该事实可能会为人所知,因此 X
不会出现在补语 class 中。
编辑
针对您的编辑,建议使用单个 :hasFinding
属性,我认为总体上看起来不错,但我可能会稍微修改一下:
:patient1 a :Patient;
:hasFinding :dyspneaFinding1 .
:dyspneaFinding1 a :Finding ;
:of :Dyspnea ;
:conclusion false .
您现在已经更清楚地将 'finding' 作为一个概念与 symptom/treatment 分开,后者是 的发现。此外,结果是肯定的还是否定的是明确建模的(而不是由 'excluded' 属性 或 'Exclusion' 类型的 presence/absense 暗示)。
(顺便说一句:因为我们 link 一个人在这里通过非打字关系(... :of :Dyspnea
)具有 class,所以我们必须依赖 OWL 2 punning使其在 OWL DL 中有效)
查询有呼吸困难发现(无论是阳性还是阴性)的患者:
SELECT ?x
WHERE {
?x a :Patient;
:hasFinding [ :of :Dyspnea ] .
}
并查询确认没有呼吸困难的患者:
SELECT ?x
WHERE {
?x a :Patient;
:hasFinding [ :of :Dyspnea ;
:conclusion false ] .
}
如果您的疾病被表示为个体,那么您可以使用否定对象 属性 断言从字面上说,例如
¬hasFinding(约翰,呼吸困难)
NegativeObjectPropertyAssertion(hasFinding john Dyspnea)
当然,如果你有很多事情不是这样的,那么这可能会有点牵扯。不过,它可能是语义上最正确的。这也意味着您的查询可以直接匹配 ontology 中的数据,这可能会更快获得结果。 (当然,当负对象 属性 成立时,您仍然会遇到尝试 推断 的问题。)
不过,如果疾病表示为 classes,这将不起作用。如果疾病由 classes 表示,那么您可以使用 class 表达式,类似于您的建议。例如,
(∀ hasFinding.¬呼吸困难)(约翰)
ClassAssertion(ObjectAllValuesFrom(hasFinding ObjectComplementOf(呼吸困难))约翰)
这与您的第三个选项类似,但我想知道它的性能是否更好。这似乎是表达您想说的内容的一种更直接的方式(即,如果某人患有某种疾病,则它不是这些疾病中的一种)。
不过我同意 ;这里有很多主观性,要获得它 "right" 实际上只是找到一些可以合理使用、对你来说表现足够好的东西,而且这似乎并不完全不自然。
我们想要建模 "something is not there" 而不是缺失信息,例如"a patient did not get chemotherapy" 或 "a patient does not have dyspnea" 的明确陈述不同于关于患者是否有呼吸困难的缺失信息。
我们考虑了几种方法,例如
- 使用否定 class:"No_Dyspnea"。但这在语义上似乎有问题,因为 class 是什么类型?它不能是 "Dyspnea" class. 的后代
- 使用 "not there" 对象属性,例如"denies" 或 "does_not_have" 然后呼吸困难根 class 的个体作为该三元组的对象。
使用空白节点描述个体属于没有呼吸困难的事物组。例如:
dat:PatientW2 a [ rdf:type owl:Class; owl:complementOf [ rdf:type owl:Restriction ; owl:onProperty roo:has_finding; owl:someValuesFrom nci:Dyspnea; ] ] .
我们觉得第三个选项是最 "ontologically correct" 的表达方式。然而,在使用它的过程中,我们在简单的场景中遇到了严重的性能问题。
我们将 Sesame 与 OWLIM-Lite 商店一起使用,并将 NCI 同义词库(280MB,大约 80,000 个概念)和另一个非常小的 ontology 导入商店并添加了两个人,其中一个拥有 complementOf/restriction class.
以下查询一直执行,我在 15 分钟后终止了它:
select *
where {
?s a [ rdf:type owl:Class;
owl:complementOf [
rdf:type owl:Restriction ;
owl:onProperty roo:has_finding;
owl:someValuesFrom nci:Dyspnea;
]
] .
} Limit 100
有人知道为什么吗?我会假设这种方法会创建很多空白节点,并且查询引擎必须遍历整个 NCI 词库并将所有空白节点与这个节点进行比较?
如果我将这个三元组放在一个单独的图中并且只查询该图,查询 returns 即时结果。
总结一下。两个基本问题是:
- 第三种方法真的最适合建模吗"something is not there"
- 这会影响查询性能吗?
编辑 1
我们讨论了提议的选项。它实际上帮助我们阐明了我们真正想要实现的目标:
我们希望能够在特定时间点声明 "Patient has Dyspnea" 或 "Patient does not have Dyspnea"。
将来 may/will 会有关于该患者的更多信息,例如he/she 现在有呼吸困难。
我们希望能够编写要求 "all patients that have dyspnea" 和 "all patients that do not have dyspnea" 的 Sparql 查询。
我们希望 Sparql 尽可能简单直观。例如。只使用一个 属性 "has_finding" 而不必知道两个属性(一个用于 "has_exclusion")。或者必须了解一些复杂的空白节点构造。
我们试过选项:
- 否定属性断言:这听起来像是解决这个问题的最佳方案,因为我们声明一个人与另一个人没有关系属性.问题是我们必须创造一个呼吸困难的人才能拥有
owl:targetIndividual
之类的东西。除了遍历整个owl:sourceIndividual
和owl:targetIndividual
链之外,我们无法找到一种轻松查询否定断言的方法。这使得 Sparql 相当冗长,并给编写查询的人增加了了解它的负担。 带有 complementOf 的空白节点:我们会用它来说明一些我们不想说明的内容。这将说明 "Patient1 can never have a finding of dyspnea"。而我们要声明 "Patient1 does not have a dyspnea finding now (or at date X)"。所以我们不应该使用这种方法。
使用 Exclusion/Inclusion 类型(选项 1 和 2):仔细查看 Jeen 的建议后,我们认为使用一般
:Exclusion
和:Inclusion
class 只有一个 属性has_finding
并且给呼吸困难的人 inclusion/exclusion 类型是最容易理解、查询和提供足够的推理能力。示例::Patient1 a :Patient . :Dyspnea1 a :Dyspnea . :Dyspnea1 a :Exclusion. :Patient1 ex:has_finding :Dyspnea1 .
这样,编写 Sparql 查询的人只需知道:
- 有一个属性
has_finding
,恰到好处地表达了用意。由于 "No dyspnea" 在技术上也是一个发现。 - 但是仅使用
has_finding
进行查询并不能提供有关此人是否实际拥有它的足够信息。查询还需要包含关于呼吸困难个体是否a :Exclusion
(或包含取决于查询目标)的三元组。 - 虽然这给查询编写者带来了一些额外的负担,但它比否定 属性 断言要少并且更容易理解。
我们非常感谢对这些结论的一些反馈!
关于建模问题,我想提供第四种选择,实际上是您的选项 1 和 2 的混合:为这些引入单独的 class(层次结构) 'excluded/missing' 症状、疾病或治疗,并有特定的排除作为实例:
:Exclusion a owl:Class .
:ExcludedSymptom rdfs:subClassOf :Exclusion .
:ExcludedTreatment rdfs:subClassOf :Exclusion .
:excludedDyspnea a :ExcludedSymptom .
:excludedChemo a :ExcludedTreatment .
:Patient a owl:Class ;
owl:equivalentClass [ a owl:Restriction ;
owl:onProperty :excluded ;
owl:allValuesFrom :Exclusion ] .
// john is a patient without Dyspnea
:john a :Patient ;
:excluded :excludedDyspnea .
可选地,您可以 link 语义排除实例 treatment/symptom/diseases:
:excludedDyspnea :ofSymptom :Dyspnea .
在我看来,这与您的其他选择一样 "ontologically correct"(老实说,这种事情非常主观),并且可能更容易维护、查询和推理。
至于你的第二个问题:虽然我不能代表你正在使用的特定推理器的行为,但一般来说,任何涉及 complementOf
的构造在计算上都非常繁重,但也许更重要的是,它可能无法捕捉到您的意图。
OWL 有一个开放世界假设,这(从广义上讲)意味着我们不能仅仅因为某个事实目前未知就断定某个事实是不真实的。您的 complementOf
构造在逻辑上将是空的 class,因为对于任何人 X
,即使我们目前不知道 X
已被诊断出患有呼吸困难,也存在将来该事实可能会为人所知,因此 X
不会出现在补语 class 中。
编辑
针对您的编辑,建议使用单个 :hasFinding
属性,我认为总体上看起来不错,但我可能会稍微修改一下:
:patient1 a :Patient;
:hasFinding :dyspneaFinding1 .
:dyspneaFinding1 a :Finding ;
:of :Dyspnea ;
:conclusion false .
您现在已经更清楚地将 'finding' 作为一个概念与 symptom/treatment 分开,后者是 的发现。此外,结果是肯定的还是否定的是明确建模的(而不是由 'excluded' 属性 或 'Exclusion' 类型的 presence/absense 暗示)。
(顺便说一句:因为我们 link 一个人在这里通过非打字关系(... :of :Dyspnea
)具有 class,所以我们必须依赖 OWL 2 punning使其在 OWL DL 中有效)
查询有呼吸困难发现(无论是阳性还是阴性)的患者:
SELECT ?x
WHERE {
?x a :Patient;
:hasFinding [ :of :Dyspnea ] .
}
并查询确认没有呼吸困难的患者:
SELECT ?x
WHERE {
?x a :Patient;
:hasFinding [ :of :Dyspnea ;
:conclusion false ] .
}
如果您的疾病被表示为个体,那么您可以使用否定对象 属性 断言从字面上说,例如
¬hasFinding(约翰,呼吸困难)
NegativeObjectPropertyAssertion(hasFinding john Dyspnea)
当然,如果你有很多事情不是这样的,那么这可能会有点牵扯。不过,它可能是语义上最正确的。这也意味着您的查询可以直接匹配 ontology 中的数据,这可能会更快获得结果。 (当然,当负对象 属性 成立时,您仍然会遇到尝试 推断 的问题。)
不过,如果疾病表示为 classes,这将不起作用。如果疾病由 classes 表示,那么您可以使用 class 表达式,类似于您的建议。例如,
(∀ hasFinding.¬呼吸困难)(约翰)
ClassAssertion(ObjectAllValuesFrom(hasFinding ObjectComplementOf(呼吸困难))约翰)
这与您的第三个选项类似,但我想知道它的性能是否更好。这似乎是表达您想说的内容的一种更直接的方式(即,如果某人患有某种疾病,则它不是这些疾病中的一种)。
不过我同意