草庐IT

模式设计和原则在知识图谱中的应用

MicroStone 2023-03-28 原文

知识图谱是一种非常强大的表示工具,它可以通过一张图表达复杂的概念,这就是为什么常说“一图胜千言”。但是,如果我们在没有明确定义的模式下创建知识图谱,就会存在一些问题。这就是为什么需要一种模式来限制链接的类型,充当文档,提供和机器可读的语义,并确保软件按照预期的方式来组织信息。

对于知识图谱而言,良好的模式设计比关系数据库更为重要和核心。不幸的是,对于如何完成相对简单的任务而言,目前缺乏详细的指导。根据我的经验,我想至少提供一些帮助。

为了更好地了解模式设计的模式和原则,我们可以使用TerminusCMS。虽然其中许多想法也适用于其他领域。

文档(Documents)

在知识图谱TerminusDB中,数据被视为由具有特定数据类型的字段组成的基本单元,这些字段可以是字符串、整数或日期等类型。这些基本单元会被组织成一个数据集合,称为“文档”。

举个例子,我们可以看看“Person”文档,以更好地理解这个概念。

{ "@type" : "Class",
"@id" : "Person",
"first_name" : "xsd:string",
"family_name" : "xsd:string",
"date_of_birth" : "xsd:dateTime"
}
这个人的信息包括姓名和出生日期,类似于关系型数据库(RDBMS)或逗号分隔值(CSV)文件中的行记录。为了让数据更加丰富,可以添加一些额外的链接。

{ "@type" : "Class",
"@id" : "Person",
"first_name" : "xsd:string",
"family_name" : "xsd:string",
"date_of_birth" : "xsd:dateTime",
"friends" : { "@type" : "Set", "@class" : "Person" }
}
在知识图谱中,我们可以将人与他们的朋友之间建立链接。这种数据结构非常适合用于社交网络或联系人管理应用程序。我们可以将每个人视为一个文档,其中包含许多数据属性,例如姓名和出生日期。此外,我们可以在文档中添加指向其他文档的链接,以建立人与他们的朋友之间的联系。这种建模方式非常简单和灵活,让我们能够方便地捆绑所有的数据属性和链接在一起。

子文档(Subdocuments)

有时,您需要在文档中包含一个内部结构,这个结构不仅仅是一个数据原子,而是与该对象有紧密联系,而不只是指向另一个对象的链接。这种类型的对象最常见的变体是注释了一些附加结构的数据。例如,我们可能希望在某个时间范围内得到数据点,该数据点具有特定的来源或可能有一个单位。

{ "@type" : "Enum",
"@id" : "Unit",
"@value" : [ "meters", "kilograms" ] }

{ "@type" : "Class",
"@id" : "UnitValue",
"@subdocument" : [],
"value" : "xsd:decimal",
"unit" : "Unit" }
有时候一个数据原子的值本身并没有意义,但是在特定对象的上下文中却很有用,例如人的身高。为了表达这种内在联系,我们可以使用子文档,它可以将数据与额外的结构注释关联起来。使用"@subdocument" : []指定一个子文档类,这个子文档将完全属于包含类,不允许其他人对其进行引用,并且当我们搜索包含文档时,它将始终以完全扩展的 JSON 文档返回。

{ "@type" : "Class",
"@id" : "Person",
"first_name" : "xsd:string",
"family_name" : "xsd:string",
"date_of_birth" : "xsd:dateTime",
"friends" : { "@type" : "Set", "@class" : "Person" }
"height" : "UnitValue",
"weight" : "UnitValue",
}
您可能已经发现,“height”和“weight”都被表示为“UnitValue”,但是可能没有使用正确的单位。为了确保单位的正确性,我们正在加入一些限制。

关系(Relationships)

并非所有关系都可以简化为一个简单的链接。xsd:decimal是表示数字的一种数据类型,然而,对于复杂的关系,通常可以使用子文档来表示它们,就像我们使用单位装饰基本类型以添加辅助信息一样。如果您有一个复杂的关系,将其升级为一级对象通常是有意义的。例如,假设我们要表示股权关系,我们可以使用子文档来描述持股人、股票数量、股份转让条款等详细信息。

{ "@type" : "Class",
"@id" : "Company",
"name" : "xsd:string" }
{ "@type" : "Class",
"@id" : "Shareholder",
"name" : "xsd:string" }
{ "@type" : "Class",
"@id" : "Company",
"@inherits" : "Shareholder" }
{ "@type" : "Class",
"@id" : "Person",
"@inherits" : "Shareholder" }
{ "@type" : "Class",
"@id" : "Shareholding",
"quantity" : "xsd:decimal",
"shares_in" : "Company",
"held_by" : "Shareholder",
"from" : "xsd:date",
"to" : { "@type" : "Optional", "@class" : "xsd:date" }}
我们的Shareholding关系包含两个不同的角色:持股公司和股东,他们可以是个人或公司。此外,我们还添加了关于这个关系的两个附加信息:持股数量和持有时间。这种一流关系链接的方法可以扩展到处理超图,即涉及两个或更多对象的关系(例如接管)。

混合(Mixins):面向方面编程的多重继承

在编程语言中,多重继承是一种有效的工具,但在数据处理中,它更加实用。混合是数据建模中可重复使用的一种方法,可以用来解决一些通用问题,例如空间、时间、来源和单位等。在我的建模经验中,我发现这些通用问题在数据建模中屡次出现,它们是跨多个领域的共同问题。

时域范围(Temporal Scope)

上面的例子Shareholding使用了时间组件,但该组件也可作为mixin(混入)在其他地方重用。mixin是一种可组合的代码单元,可在不同类或对象中进行重复利用,以实现更高的代码复用性和灵活性。因此,将时间组件提取为mixin可以在其他数据建模中方便地进行复用,提高建模效率和代码质量。

{ "@type" : "Class",
"@id" : "TemporalScope"
"from" : "xsd:date",
"to" : { "@type" : "Optional", "@class" : "xsd:date" }
}
在数据建模中,时间范围的起始日期(from)是必须要有的,因为它描述了一些事情的开始时间。但是,结束日期(to)是可选的,这样可以建模尚未结束的时间范围。当然,并不总是需要这样做,但通常这是一种非常有用的方法。

此外,我们可能还需要建模只发生一次的事件,即在某个特定时刻发生且不再重复发生的事件,例如一个人的生日或一场比赛的开始时间。

{ "@type" : "Class",
"@id" : "Event"
"at" : "xsd:date"
}

空间范围(spatial scope)

在知识图谱中,我们可以利用几何形状为对象添加空间范围,这可以通过继承来实现。我们可以将不同的几何形状组合在一起来表示空间范围,例如矩形、圆形或多边形。这种方法使我们能够描述一个实体或概念在地理上的位置或空间范围。

{ "@type" : "Class",
"@id" : "GeographicScope",
"geometry" : "Geometry" }
在这个上下文中,“Geometry”所指的是GeoJson中的一个类,具体指的是“Geometry类”。

溯源(Provenance)

为了更好地了解某些信息,通常需要记录相关资源的来源。例如,当我们从网站等途径获取资源时,这种记录就很常见。在这种情况下,我们可能需要创建一个继承Event和Source类的对象来记录这些信息。

{ "@type" : "Class",
"@id" : "Source",
"source" : "xsd:anyURI"
}
{ "@type" : "Class",
"@id" : "WebScrape",
"@inherits" : ["Event", "Source"],
"page" : "xsd:string",
}

集合体(Collections)

在知识图谱中,有许多不同的方式可以对集合进行建模。TerminusDB 实现了三种不同的方法,旨在尝试简化建模过程,这三种方法是:Set、List和Array。了解这三种方法之间的差异非常重要:Set表示集合,List表示列表,而Array则表示数组。

集合(Set)

Set是三种集合模型中最简单的一种,因为它没有顺序,实际上只是一条边,可以包含多个元素。在图中,具有三个元素的Set集合可以表示为以下形式:

数组(Array)

Array是一个更复杂的对象,它通过索引来对元素进行编码,并且可以根据位置来访问它们。与Sets和Lists不同,Array具有固定的大小,其元素是有序的。此外,Array还提供了一些额外的功能,使其与Sets和Lists区别开来。

数组中的每个值元素都有一个附加的(隐藏)间接对象,带有索引(或多维数组的多个索引)。这使得我们不仅可以有顺序,还可以有多个维度来表示“间隔”。当返回 JSON 中的值时,我们将返回一个多维数组,其中包含未填充区域的null字段。但实际上,这些未填充区域并没有在数据库中出现。

列表(List)

List 是直接从 RDF 数据中提取 rdf:List 并使用 rdf:first 和 rdf:rest 字段来表示。三个元素的列表结构如下所示:

rest→ rest→ rest→ rdf:nil
first first first
v0 v1 v2
链表式结构具有潜在的技术优势。相较于数组,您可以在列表中的任何位置插入新元素,而不必在给定元素之后重新索引所有内容。但是,链表式结构需要遍历图中的长链来解码列表,这可能会对性能产生影响。在列表非常长时,它可能会导致解码时间显著延长,因此需要权衡其优缺点来选择适合特定场景的数据结构。

结论

通过使用知识图谱,可以实现更加轻松地操作和发现数据。知识图谱是一个基于图形结构的数据模型,可以将各种实体和概念以及它们之间的关系表示为节点和边,使得数据之间的关系和结构更加清晰和易于理解。在使用知识图谱进行数据建模后,用户可以方便地进行数据操作和发现,从而更加高效地利用数据。

有关模式设计和原则在知识图谱中的应用的更多相关文章

  1. ruby - 如何从 ruby​​ 中的字符串运行任意对象方法? - 2

    总的来说,我对ruby​​还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用

  2. ruby - 其他文件中的 Rake 任务 - 2

    我试图在一个项目中使用rake,如果我把所有东西都放到Rakefile中,它会很大并且很难读取/找到东西,所以我试着将每个命名空间放在lib/rake中它自己的文件中,我添加了这个到我的rake文件的顶部:Dir['#{File.dirname(__FILE__)}/lib/rake/*.rake'].map{|f|requiref}它加载文件没问题,但没有任务。我现在只有一个.rake文件作为测试,名为“servers.rake”,它看起来像这样:namespace:serverdotask:testdoputs"test"endend所以当我运行rakeserver:testid时

  3. ruby-on-rails - Ruby net/ldap 模块中的内存泄漏 - 2

    作为我的Rails应用程序的一部分,我编写了一个小导入程序,它从我们的LDAP系统中吸取数据并将其塞入一个用户表中。不幸的是,与LDAP相关的代码在遍历我们的32K用户时泄漏了大量内存,我一直无法弄清楚如何解决这个问题。这个问题似乎在某种程度上与LDAP库有关,因为当我删除对LDAP内容的调用时,内存使用情况会很好地稳定下来。此外,不断增加的对象是Net::BER::BerIdentifiedString和Net::BER::BerIdentifiedArray,它们都是LDAP库的一部分。当我运行导入时,内存使用量最终达到超过1GB的峰值。如果问题存在,我需要找到一些方法来更正我的代

  4. ruby-on-rails - Rails 3 中的多个路由文件 - 2

    Rails2.3可以选择随时使用RouteSet#add_configuration_file添加更多路由。是否可以在Rails3项目中做同样的事情? 最佳答案 在config/application.rb中:config.paths.config.routes在Rails3.2(也可能是Rails3.1)中,使用:config.paths["config/routes"] 关于ruby-on-rails-Rails3中的多个路由文件,我们在StackOverflow上找到一个类似的问题

  5. ruby-on-rails - Rails - 子类化模型的设计模式是什么? - 2

    我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co

  6. ruby - 将差异补丁应用于字符串/文件 - 2

    对于具有离线功能的智能手机应用程序,我正在为Xml文件创建单向文本同步。我希望我的服务器将增量/差异(例如GNU差异补丁)发送到目标设备。这是计划:Time=0Server:hasversion_1ofXmlfile(~800kiB)Client:hasversion_1ofXmlfile(~800kiB)Time=1Server:hasversion_1andversion_2ofXmlfile(each~800kiB)computesdeltaoftheseversions(=patch)(~10kiB)sendspatchtoClient(~10kiBtransferred)Cl

  7. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  8. ruby-on-rails - Rails - 一个 View 中的多个模型 - 2

    我需要从一个View访问多个模型。以前,我的links_controller仅用于提供以不同方式排序的链接资源。现在我想包括一个部分(我假设)显示按分数排序的顶级用户(@users=User.all.sort_by(&:score))我知道我可以将此代码插入每个链接操作并从View访问它,但这似乎不是“ruby方式”,我将需要在不久的将来访问更多模型。这可能会变得很脏,是否有针对这种情况的任何技术?注意事项:我认为我的应用程序正朝着单一格式和动态页面内容的方向发展,本质上是一个典型的网络应用程序。我知道before_filter但考虑到我希望应用程序进入的方向,这似乎很麻烦。最终从任何

  9. ruby-on-rails - Rails 3.2.1 中 ActionMailer 中的未定义方法 'default_content_type=' - 2

    我在我的项目中添加了一个系统来重置用户密码并通过电子邮件将密码发送给他,以防他忘记密码。昨天它运行良好(当我实现它时)。当我今天尝试启动服务器时,出现以下错误。=>BootingWEBrick=>Rails3.2.1applicationstartingindevelopmentonhttp://0.0.0.0:3000=>Callwith-dtodetach=>Ctrl-CtoshutdownserverExiting/Users/vinayshenoy/.rvm/gems/ruby-1.9.3-p0/gems/actionmailer-3.2.1/lib/action_mailer

  10. ruby-on-rails - Rails 应用程序之间的通信 - 2

    我构建了两个需要相互通信和发送文件的Rails应用程序。例如,一个Rails应用程序会发送请求以查看其他应用程序数据库中的表。然后另一个应用程序将呈现该表的json并将其发回。我还希望一个应用程序将存储在其公共(public)目录中的文本文件发送到另一个应用程序的公共(public)目录。我从来没有做过这样的事情,所以我什至不知道从哪里开始。任何帮助,将不胜感激。谢谢! 最佳答案 无论Rails是什么,几乎所有Web应用程序都有您的要求,大多数现代Web应用程序都需要相互通信。但是有一个小小的理解需要你坚持下去,网站不应直接访问彼此

随机推荐