“自我描述的” Neo4j 图数据库(第 1 部分)
#SmartData Metamodel 子图设计在 FactMiners 的社交游戏生态系统中 - 第 1 部分,共 2 部分
作者:Jim Salmons
FactMiners.org 和 Softalk Apple 项目
日期:2014 年 1 月 25 日
修订:0.2
这两部分 GraphGist 探讨了在 Neo4j 图数据库应用中使用的“metamodel 子图”设计模式
第 1 部分 这篇关于 metamodel 子图 设计及其工作原理的介绍性 #GraphGist。
基于我们的介绍性想法,我们开始构建 FactMiners Fact Cloud(一个“自我描述的” Neo4j 数据库)的 metamodel,它将捕获锁定在 Softalk 杂志(1980-84 年)48 期月刊 中的丰富的技术史。用例场景是 FactMiners 玩家,他是 The Softalk Apple 项目的代理。该玩家(拥有 Fact Cloud 所有者/创建者权限 - 参见第 4 部分)使用 FactMiners Fact Cloud 向导设置 Softalk 杂志 Fact Cloud —— 也就是说,使用向导创建并维护 Fact Cloud 的 metamodel 子图 —— 以便 FactMiners 社交游戏玩家可以帮助构建 Fact Cloud,从而解锁项目在线数字档案中的数据。
我们将详细介绍一个双人 FactMiners 游戏场景,其中“游戏场”是包含 Top 30 畅销书列表的 Softalk 页面。其中一名玩家在一轮事实挖掘中“占领”了该列表区域。Cypher 查询片段展示了 metamodel 子图如何帮助 FactMiners 玩家在 Softalk 杂志的 FactMiners Fact Cloud 中查找、输入、验证和探索事实。[注意:此 GraphGist 内容已纳入我的 #MCN2014 演示文稿,“Where Facts Live: GraphGist Edition”。请观看我的 MCN 演示文稿中嵌入视频的后半部分,了解页面分割游戏示例。]
本 GraphGist 系列最后介绍了“META:Process”分区,其中介绍了 metamodel 的“我能做什么?”和“我如何做?”功能并进行了演示。[注意:尚未撰写此内容的完整具体处理方法,但我的 #cidocCRM 相关博客文章中贯穿了信息线索:https://goo.gl/dpbhPs。更多内容将在展开时提供。]
第 1 部分:“自我描述的” Neo4j 图数据库是什么?
模式描述 一个自我描述的 Neo4j 数据库是指包含一个关于该数据库中数据的 metamodel 子图的数据库。也就是说,图数据库内部有一个图数据库(即节点和关系的非连接子集),这些数据构成了一个模型,它详细地告诉我们关于包含该 metamodel 的数据库中找到或允许存在的 实际 数据的信息。典型用途 交互式应用,当需要图数据库在捕获和表示稀疏、松耦合但语义丰富的信息空间(例如 Softalk 杂志 48 期等复杂杂志结构中的编辑和广告 事实)时既灵活又规范。MetaDATA 还是 MetaMODEL? 模式描述提到了“关于数据的数据”。这听起来像 元数据 (metadata)。是什么让这种模式是关于 metamodel 而不是 metadata 呢?正如本 GraphGist 系列将演示的,所提出的 metamodel 子图 是一个非常丰富的描述性模型,即 metamodel,它不仅关于数据库中数据的 结构,还包括关于访问和工作流的 流程 信息,以便 metamodel 感知的瘦客户端工具(以及在我们的例子中,游戏)能够灵活地适应,代表“自我描述的”数据库提供编辑、可视化和其他访问服务。
让我们看一下最简单的情况——两个节点通过关系连接,以及描述它的 metamodel 构造。
新闻界有一句老话说:“狗咬人 不算新闻,但 人咬狗 才是新闻。”。我们将使用这句格言作为我们介绍性例子的基础。
我们首先向一个空的、到目前为止非自我描述的 Neo4j 数据库中添加一些“新闻”。
CREATE (:MAN {name: "Joe"}) - [:BITES] -> (:DOG {name: "Fido"})
一个叫乔的男人(我们的记者为此独家新闻跑遍了街头巷尾)咬了一只叫菲多的狗……十一点看新闻!
为了使这个数据库自我描述,我们在数据库中添加一些节点和关系到这个专用的、非连接的子图。要创建 metamodel 子图,我们只需在我们希望包含在 metamodel 中的任何节点上包含 META 标签。这个 Cypher 查询创建了描述根据我们旧新闻格言的 咬人新闻 的(必要/允许的)结构的 metamodel 元素。
CREATE
(man:META:Nodes {type: "MAN", name: "MAN"}),
(dog:META:Nodes {type: "DOG", name: "DOG"}),
news = (man - [:FROM_NODE] ->
(:META:Relationships {type: "BITES", name: "BITES"})
- [:TO_NODE] -> dog)
当前内置的 GraphGist 图可视化水平使用节点颜色反映基于标签的集合成员关系。随着时间的推移和足够的“需求”,我确信我们将拥有更多 GraphGist 输出组合和样式选项。GraphGisting 作为一种探索性设计和交流媒介,非常出色,使用它肯定会变得更好。当 GraphGist 作者/开发者能够动态生成有用的可视化(如下所示,将基于标签的集合成员关系显示为区域包含)时,那将非常棒。 |
注意数据库中的 BITES 关系是如何通过 metamodel 中的 BITES 节点建模的。这种转换映射使我们能够明确关于现在成为 自我描述的 Neo4j 数据库数据中发现或允许存在的关系的 FROM_NODE 和 TO_NODE 特征。这个 关于关系的节点 实际上是它自己在 metamodel 中关于 BITES 关系的微模型 根,该关系将表现在数据库的非元数据中。
上面的 Cypher 查询中反映了一些额外的 metamodel 结构化 提示,它们共同进一步描述了我们的 咬人新闻 数据库中的数据模型。
-
metamodel 中有两个带标签的子集:节点 和 关系。结构化的子集标签对于对 metamodel 子图 的这种探索的语义至关重要。
-
META:Nodes 子集中的节点有一个 type 属性。这意味着您将在非元数据中找到标签等于该 type 属性值的节点。例如,metamodel 中的 (:META:Nodes {type: "MAN"}) 告诉我们非元数据中将有标签为 (:MAN) 的节点。
-
类似的映射适用于 META:Relationships 中的节点,其中 metamodel 节点中的 type 属性对应于非元数据中关系的 :RELTYPE 标签。
这个入门示例故意超简单。它无法揭示应用 metamodel 子图 设计模式的全部潜力,也未反映其实际复杂性。在本 GraphGist 系列的第二部分,我们将开始为 Softalk 杂志在线数字档案的配套 FactMiners Fact Cloud 构建 metamodel。除了阐述 metamodel 的结构外,我们还将触及实际复杂性,例如处理节点和关系的属性等。
但首先,那又怎样?我现在有了 metamodel,能用它做什么?
自我描述:那么谁在“听”?为了什么?
术语 自我描述的 Neo4j 数据库表明有人或有东西正在“听取”并理解该描述。这个“听者”通常是一个瘦客户端应用,可以通过插件架构进行动态配置,以提供编辑、报告、可视化或其他访问服务。这些瘦客户端利用其 metamodel 感知能力来配置编辑器,从而确保数据库中不会输入 错误数据。或者,对于现有的非结构化数据,此类工具可以提供 智能助手 服务,通过交互式会话来整理和增值数据,以创建和扩展关于数据的 metamodel 子图。这是一个非常基础的示例,说明它将如何工作……
我们负责 (Man)--(Dog) 报道的记者设立了一个“咬人新闻热线”,接收关于镇上可疑咬人事件的匿名报告。人们填写一份网络表单,尽可能多地提供关于事件的信息。我们将处理通过热线收到的三个提示,接着是一个 Cypher 查询,热线 metamodel 感知的瘦客户端应用可能会使用该查询来查找和验证具有新闻价值的咬人事件。
// Create a tips to be tested...
//
// Tip 1: "Joe bites Fido." (Case: Known incident already in data)
MATCH (joe:MAN {name: "Joe"}) - [known_bite:BITES] -> (fido:DOG {name: "Fido"})
SET known_bite.status = "unconfirmed"
// Tip 2: "Fido bites Joe." (Case: Known actors, role mismatch)
MERGE fido - [:BITES {status: "unconfirmed"}] -> joe
// Tip 3: "Johnny bites Rover." (Case: Unknown actors, fact check assist)
CREATE (:UNK {name: "Johnny"}) - [:BITES {status: "unconfirmed"}] -> (:UNK {name: "Rover"})
WITH known_bite
// Let's see how our metamodel can help us figure out about the newsworthiness
// of these biting incident tips.
//
// First, let's find out what we know about biting incidents...
MATCH (biter) --> (bites:META:Relationships {type: "BITES"}) --> (bitee)
WITH biter, bites, bitee
// Now, round up our unconfirmed tips of bite incidents and investigate their newsworthiness...
MATCH (accused_biter) - [incident:BITES {status: "unconfirmed"}] -> (alleged_victim)
WITH biter, bites, bitee, accused_biter, incident, alleged_victim,
accused_biter.name + " " + lower(type(incident)) + " " + alleged_victim.name + "." as unconfirmed_tip,
// First, fact-check the accused Biter...
CASE
WHEN "UNK" IN labels(accused_biter)
THEN "Biter: FACT CHECK - Need to confirm " + accused_biter.name + " is a " + biter.type + ". Otherwise, no news."
// We have a potentially newsworthy biter...
WHEN biter.type IN labels(accused_biter)
THEN "Biter: CONFIRMED - " + accused_biter.name + " is a " + biter.type + "."
// The known Biter is of the wrong type, no news...
WHEN NOT (biter.type IN labels(accused_biter))
THEN "Biter: NO NEWS - " + accused_biter.name + " is NOT a " + biter.type + "."
// Unhandled case - The metamodel might need refining...
ELSE "Biter: ALERT - I am confused about " + accused_biter.name + "'s role in this biting incident. A report is being logged to the Metamodel Police. Nothing to see here. Step away from the program. This just became a crime scene..."
END as biter_assessment,
// Next, check the alleged victim...
CASE
WHEN "UNK" IN labels(alleged_victim)
THEN "Victim: FACT CHECK - Need to confirm " + alleged_victim.name + " is a " + bitee.type + ". Otherwise, no news."
// We have a potentially newsworthy alleged_victim...
WHEN biter.type IN labels(accused_biter) AND bitee.type IN labels(alleged_victim)
THEN "Victim: CONFIRMED - " + alleged_victim.name + " is a " + bitee.type + ".<br>CONGRATULATIONS! We have NEWS! :-)"
// If both actors are appropriate, we have a newsworthy tip! :-)
WHEN bitee.type IN labels(alleged_victim)
THEN "Victim: CONFIRMED - " + alleged_victim.name + " is a " + bitee.type + "."
// The known alleged_victim is of the wrong type, no news...
WHEN NOT (bitee.type IN labels(alleged_victim))
THEN "Victim: NO NEWS - " + alleged_victim.name + " is NOT a " + bitee.type + "."
// Unhandled case - The metamodel might need refining...
ELSE "Victim: ALERT - I am confused about " + alleged_victim.name + "'s role in this biting incident. A report is being logged to the Metamodel Police. Nothing to see here. Step away from the program. This just became a crime scene..."
END as bitee_assessment
RETURN unconfirmed_tip as `Tip`, biter_assessment + " <br> " + bitee_assessment as `Tip Assessment Results`
经过一番挖掘,我们的记者确认了不完整的“Johnny 咬 Rover”提示中所涉及的物种。当记者输入这些更新的事实时,metamodel 感知的瘦客户端会重新应用其“咬人新闻”事实核查流程,并确认我们有一条突发咬人新闻报道。
就这样。仔细想想还不赖。我们在数据库中添加了三个节点和两个关系,使其(最起码)自我描述。而且由于我们对数据库中这些数据位点的思考方式与数据库中其他数据不同,我们能够执行“咬人新闻热线”所需的事实核查(数据整理)任务。
但那又怎样?那个小小的 metamodel 可能帮助我们完成了事实核查任务,但我仍然看到执行实际事实核查计算的 Cypher 代码中包含大量领域特定知识。确实如此,但这归因于“编码器上下文”。就这个入门示例而言,我以一种“讲故事”般的认知过程编写了这些查询,这种过程帮助我编写代码,就像 咬人新闻热线 上下文帮助您阅读和理解我的代码一样。
关键在这里。那个 可读性上下文 是表面的。从本质上讲,这个提示事实核查程序完全可以通过在 metamodel 感知客户端的泛化上下文中编写的代码来完成。换句话说,这个
MATCH (accused_biter) - [incident:BITES] -> (alleged_victim)
RETURN *
可以很容易地在泛化上下文(例如 RDF 三元组)中编写。
// RDF-like 'fact' context
MATCH (subject) - [verb:PREDICATE] -> (object)
RETURN *
或者您可以用任意数量的其他词汇/上下文重写。然而,妙处在于,一旦我们在 metamodel 感知的瘦客户端的插件库中拥有了良好的泛化 metamodel 处理算法核心,我们就会极大地减少首先编写领域特定代码的需求。使用像 FactMiners Fact Cloud Wizard 这样的 metamodel 构建工具,几乎所有的领域特定知识都将移入 metamodel,而不是锁定在特定实例的源代码中。
这将我们带入了构建 FactMiners 生态系统可能带来的意想不到的良好后果的领域。我相信通过 FactMiners 探索的重大想法将在游戏之外找到广泛的应用。
继续第 2 部分……
这里简要探讨的想法是开始在 本 GraphGist 的第 2 部分 中构建 Softalk 杂志 Fact Cloud metamodel 的基础。
此页面有帮助吗?