第1章 关联数据简介

第1章 关联数据简介

本章内容

  • 关联数据概述

  • 关联数据原则

  • 关联数据基础

  • 对关联数据应用程序的剖析

如果上司要求你每天为1500个包含多种语言和字符集的电视和广播节目制作网页,但无法配备足够的人手时,你该怎么办?如果需要为每支乐队和他们录制的歌曲发布Web内容并每天更新时,你该怎么办?如果需要为每个动物物种及其栖息地(包括它们的濒危状态)创建网页,但企业并不掌握这些信息时,你又该怎么办?

在预算被削减时,英国广播公司(BBC)的开发团队就同时面临这三项挑战。我们很快将讨论他们如何通过关联数据(Linked Data)解决了上述所有问题。

关联数据让万维网成为一个全球性数据库,我们称之为数据网(Web of Data)。开发人员可以同时查询多个数据源的关联数据,并动态合并查询结果,这是传统数据管理技术很难或根本无法做到的。设想一下,藉由关联数据,只需一步就能收集任何所需的数据——这听起来似乎不可思议。诚然,采用传统技术的确难以做到这一点,但关联数据则有所不同,本章将对此进行介绍。

在学习这一章之前,读者应对HTML、URI、HTTP等基本的Web技术有所了解。我们将向读者介绍关联数据,在各种背景下讨论其应用,论述指导关联数据使用的4项原则,并通过第一个应用程序展示关联数据的用法。

我们可能会引用某些读者尚不熟悉的资源,如MusicBrainz(一种开放的音乐百科全书)。不过无需担心,我们会提供相关链接,以便读者了解相应的背景信息。

1.1 关联数据定义

万维网充斥着海量数据,数据以PDF、TIFF(标签图像文件格式)、CSV(逗号分隔值)、Excel电子表格、Word文档中的嵌入表格以及各种纯文本格式发布。这些文件与HTML和其他文档之间存在链接关系。从某种意义上说,它们是可以链接到的数据。不过这种数据存在一定的局限性,因为它们采用适合人类用户使用的格式,一般需要专门工具进行读取,导致自动化进程难以访问、搜索或重用。人们通常需要对这些数据作进一步处理,以便将它们导入新项目,或根据数据作出决策。

我们希望能有一种通用的机制,使得任何人都能读取和重用万维网上的数据。用户不仅需要链接到数据所在的文件,也需要链接到相关的数据。用户希望自己的数据能与其他相关数据链接起来,从未谋面的用户也可以重用数据。

本书将向读者介绍在万维网上使用、重用与发布数据的新机制,以便企业防火墙两侧的自动化进程都能对数据进行重用。这套机制称为关联数据,它是在万维网上发布和连接结构化数据的最佳实践,遵循万维网联盟(World Wide Web Consortium,W3C)制订的国际标准。

如果读者对HTTP、URI、超链接等概念已有所了解,那么对关联数据所用的某些技术应该不会陌生。我们希望在万维网上发布数据,并使用URI来标识数据元素以及元素之间的关系。与网页之间的超链接类似,关联数据可以通过URI将数据元素链接在一起。关联数据是万维网上的数据,它本质上仍是数据,其结构与万维网并无二致。这些概念被归纳为关联数据原则(Linked Data principles),1.4节将对此作进一步讨论。

关联数据的质量高低取决于在多大程度上遵循这些原则。关联数据的五星评分系统如下。

★ 数据以任何格式存在并可用(如扫描图像)。

★★ 数据可作为机器可读的结构化数据(如Excel电子表格)。

★★★ 数据以非专有的格式存在并可用(如CSV)。

★★★★ 数据采用W3C制订的开放数据标准发布。

★★★★★ 上述几条规则均适用,数据还能链接到其他用户的数据。

五星评分系统是逐步累积的。每增加一颗星,表示数据符合前一步的标准。开发人员对于创建能达到五星标准的关联数据深感自豪。反之,如果没有达到标准,意味着有更多的工作要做,比如将数据转换为五星格式、增加更多的链接或请求数据源提供质量更高的数据。通过创建五星关联数据,可以更好地利用万维网上的数据。

W3C负责制订各种万维网标准,包括开放数据模型以及适用于该模型的数据格式。本章将讨论RDF(Resource Description Framework,资源描述框架),RDF用于获取最高质量的关联数据。

图1.1所示的W3C咖啡杯给出了五星系统的释义。

这里再重复一遍关联数据的定义:它是在万维网上使用标准格式和接口发布数据的一系列技术。遵循相关标准的数据称为关联数据。

例如,可以将维基百科(Wikipedia)上的大部分内容视为结构化数据。维基百科的文章页面右上方有一个文本框,包含名称、日期、地点以及指向其他内容的链接。DBpedia项目[1]从维基百科的文章中提取出结构化数据,并发布到万维网上。遵循关联数据原则发布的数据即为关联数据,可以被有权访问数据的其他用户所使用。

..\17-1007 图\0101.tif

图1.1 五星关联数据马克杯,可从cafepress.com上订购。用户既可以订购印有“Open”(开放)和“Open License”(开放许可)字样的马克杯,也可以订购没有上述标记的马克杯。前者是关联开放数据(Linked Open Data)马克杯,后者是关联数据(Linked Data)马克杯。马克杯的销售收入用于支持W3C的工作

关联数据的一个神奇之处在于,它很容易就能与其他关联数据组合在一起,从而构成新的知识,这也是探索并使用关联数据的最好理由。传统的数据管理技术使得大部分用户数据被封闭在不易重组的孤岛(silo)[2]中。在执行指定任务之前,用户需要编写程序以查找、访问、转换与合并孤岛中的数据。而关联数据有助于将数据从孤岛中解放出来,因为合并不同数据源的关联数据并非难事。

关联数据的另一个有用之处在于,它是自文档化的(self-documenting):只要在万维网上解析某个术语,就能立即了解它的含义。这使得关联数据成为数据共享中一种奇妙的新技术。

设想从各种来源采集数据,以执行分析或混聚(mash-up)操作。我们可以从DBpedia和万维网的其他关联数据中抓取数据,将它们组合在一起,从而获得所需的数据集(dataset)。

接下来,我们将介绍源自公共万维网的编程思想,但并非所有关联数据都需要公开。关联数据技术也被广泛部署在专用网络的企业防火墙之后。本书介绍的所有内容都可以采用公共数据、私有数据或二者的混合进行部署。

1.2 关联数据并非万能

读者可能有所疑虑,关联数据的功能是否太过强大而难以实现?答案是否定的。关联数据以万维网为基础构建,具有和万维网相同的优点和不足。

关联数据并非灵丹妙药,它无法解决数据质量或服务故障所引起的问题,也无法提高分布式查询的效率。改变模式术语(schema term)的定义同样如此。如果术语含义发生变化,开发时数据可能更难理解。

但是,关联数据确实提供了多种新的手段,以应对现有数据管理遇到的挑战。

数据质量是所有数据管理系统都要面对的问题。关系数据库或网站中的脏数据(dirty data)很快就会变为脏关联数据(dirty Linked Data)。关联数据通常不会以特定于应用程序的方式发布,这可能会暴露之前并不透明的数据清洗(data cleanliness)问题,同时让问题更容易被发现。许多网站对关联数据的结构进行调整,以便在重用前对这些数据进行审查甚至加工(curation),我们将在后面的BBC示例中加以说明。其他人无法忍受脏数据。一如既往,决定权掌握在用户手中。

在使用Web服务的关联数据时,如果出现服务关闭或暂时不可用的情况,应该如何处理呢?基于可靠性和效率的考虑,大部分用户不会在生产环境中构建需要实时查询分布式数据的服务。我们可以将某些远程数据的本地副本视为一种缓存。远程服务出现故障,仅仅意味着在服务恢复正常或启用替代服务之前,数据可能不是最新的。

那么,改变模式术语意味着什么?由于关联数据模式术语通过HTTP URI进行标识,如果某个术语的含义发生变化,那么将其迁移到另一个URI相对容易一些。即便不更改术语的URI,通常也可以(并应该)将术语定义的时间和位置记录下来。此外,我们甚至还能对等效术语进行检查。关联数据具备不同层次的灵活性,有助于用户调整模式。

我们可以将这些挑战置于万维网的背景下进行思考。由于早期的超文本系统只部署在一台设备上,所以能确保所有链接都被解析为有效的资源。被链接的资源(或意识到被链接的资源)可以计算链接的数量,并自动链接回去。大部分超文本的研究人员之所以不喜欢早期的万维网,正是因为后者无法提供这些方便的功能。当链接无法解析时,万维网会频繁显示404错误消息。不过,万维网也有一些超文本系统所不具备的重要特性,特别是可扩展性和分布式作者身份(distributed authorship)。对用户而言,这些特性比链接管理更重要。

与之类似,关联数据并未解决分布式数据管理长期以来存在的问题,甚至会引入新的问题。例如,至少一部分数据元素需要采用复杂的网址来命名,导致数据格式难以读写。但和万维网一样,关联数据的优点远远超过它的缺点,本书将对此予以说明。具体而言,我们将介绍如何利用关联数据来维护通过其他机制发布数据时经常丢失的上下文。我们甚至可以在事后将上下文重新放回数据,使得从未谋面的用户也能通过新方法使用数据。与万维网类似,一旦掌握关联数据,就会对它爱不释手。

1.3 关联数据实战

对于“如何与他人分享我们的知识”这个由来已久的问题,关联数据技术给出了一个新的答案。关联数据是一个通用的概念,理论上说,它可以用于描述任何内容。

关联数据将结构化数据置于万维网上,这些数据可以被发现、共享并与其他用户的数据进行合并。关联数据将结构化数据从专有容器(proprietary container)中释放出来,使得任何用户都可以使用它。

1.3.1 释放数据

纵观历史,人们经常混淆信息和承载它的容器。虽然人们真正关心的是容器内的信息,但仍然建立了专门的机构来保护容器(而非信息本身)。历史上最早的图书馆致力于保护卷轴和图书,而不是其中的文字。图书管理员限制读者借阅图书,以便图书能保存更长的时间。

最终,人们将图书内容转换为可以在互联网上传播的信息比特,从而让内容得以释放。这样做的优点很多,不过人们也认识到,不能将图书馆和书店混为一谈。本书写作期间,正值美国最大的连锁书店企业之一Borders Group(博德斯集团)宣告破产,并关闭了数百家实体书店[3]。图书馆的藏品已经发生了翻天覆地的变化,读者现在不仅能借阅图书和访问互联网,也能借阅音乐、视频和有声读物。图书馆还举办各类课程并向俱乐部出租场地,在面对Google、Apple、Amazon等互联网巨擘的冲击时努力保持自己的尊严。

音乐经历了同样的转变,从最初销售磁带和CD,发展到销售可以在iPod、计算机、家庭音响等各种设备上播放的信息比特。所有这一切都是拜万维网所赐。

在网络时代,用户数据(比如几年前的图书和音乐)保存在哪里呢?大部分用户数据保存在关系数据库、电子表格等专有容器中,一般通过创建数据的容器(无论是关系数据库还是电子表格程序)进行读取。用户数据是分层的,支持数据的系统同样如此。BBC开发团队采用一种崭新的方式解决了这个问题,他们从万维网中提取信息并进行加工,以确保信息的准确性。

然而,合并分层数据并非易事,在这个过程中可能会产生信息孤岛。如果手动将信息置于不同的容器中,那么在使用多个来源的数据时,必须先在脑海中将它们组合在一起,但这通常会导致信息的来源难以追踪。

某些情况下,我们希望将数据保存在专有容器中以防窥探,个人财务信息就是一个很好的例子。不过,我们仍然希望通过网络保持财务往来。如果银行采用通用格式处理用户数据就比较容易实现这一点,就像使用HTTP来处理网页一样。而其他时候,我们则希望数据是开放和免费的。例如,我们想确定住所附近有哪些工厂正在排污,或者哪位艺术家又创作了一首新的热门歌曲。

我们如何像释放图书和音乐内容那样释放数据呢?一种方案是将数据迁移到万维网。正如万维网可以链接相关文档那样,它也可以将相关数据链接起来,特别是当所有人都采用通用的数据格式和访问方法时。

1.3.2 关联数据在Google富摘要和Facebook“点赞”中的应用

即便读者可能还未觉察到关联数据在幕后所起的作用,但也可以看到它的优势所在。无论Facebook的“点赞”(Like)按钮[4]、Google的增强型搜索结果还是BBC的美丽野生动物和音乐网页,都是关联数据在实际中的应用。

如图1.2所示,Google在2009年引入了富摘要(rich snippets)[5],以强化搜索结果。

..\17-1007 图\0102.tif

图1.2 Google富摘要提供格式美观的搜索结果,能将用户点击率提高15%~30%

富摘要程序由RDFa(Resource Description Framework in Attributes,属性中的资源描述框架)提供支持。RDFa是一种用于网页编码的关联数据格式,后面的章节将对此作详细介绍。例如,用户可以识别网页中的电话号码,而通过浏览器显示中隐藏的HTML属性对其进行标记,搜索引擎也可以识别电话号码,并利用这些信息构建针对性更强的搜索结果。大型消费电子产品零售商Best Buy发布的数据显示,藉由RDFa的应用,其Google搜索结果的点击率提高了15%~30%。

Facebook于2010年4月引入了“点赞”按钮。当用户点击网页中的“点赞”按钮时,该用户的Facebook资料将随之更新,以反映用户喜欢网页中讨论的内容,这些内容可以是文章、电影或餐厅。“点赞”按钮(如图1.3所示)同样由RDFa提供支持。

..\17-1007 改图\0103.tiff

图1.3 Facebook“点赞”按钮可以被嵌入到任何网页中,Facebook使用这个功能 将外部页面与Facebook的社交图谱连接在一起

RDFa属于描述结构化数据的一系列标准,这些标准统称为RDF。RDF并非数据格式,它定义了一种简单的方法来表示任意数据元素之间的关系,这些元素可以通过各种标准格式进行序列化。RDF为关联数据提供了一个通用的数据模型,特别适合表示万维网上的数据。关联数据采用RDF作为数据模型,并以某种语法表示。此外,关联数据还使用一种名为SPARQL的标准查询语言。本章稍后将介绍RDF数据模型,第 2 章将对此作进一步探讨。后续章节将介绍如何在关联数据项目中使用这些数据格式以及查询语言。

1.3.3 关联数据拯救了BBC

接下来,我们将注意力转向BBC,讨论开发团队如何利用关联数据从万维网采集信息并确保其准确性,以及通过重用信息来自动创建深层次的复杂网站。

BBC所需的数据散落于万维网的各种公共服务中。开发团队意识到,可以收集并重新利用某些数据,以加快新网站的开发速度。

BBC采用关联数据为 3 种Web属性生成相应的Web存在(Web presence),它们是BBC Programmes[6]、BBC Music[7]以及Wildlife Finder[8]。仅BBC Programmes本身,每天就会产生1500多个电视和广播的Web存在。为完成这个高难度的任务,开发团队使用万维网上已经存在的公共数据。

BBC对世界野生动物基金会(WWF)、MusicBrainz[9]、DBpedia等各种来源的关联数据进行收集、过滤和重用。如图1.4所示,DBpedia从维基百科(用户在维基百科页面右上角看到的内容)提取结构化数据,并将其转换为关联数据。藉由这些关联数据,BBC进一步丰富了广播节目中讨论的音乐艺人和野生物种的信息。BBC采用类似的方式管理从其他网站收集的关联数据。由于所有关联数据共享同一个数据模型(将在第2章讨论),这些网站的数据可以立即合并。

..\17-1007 图\0104.tif

图1.4 DBpedia将从维基百科信息框中提取的结构化信息转换为关联数据,BBC利用来自DBpedia和其他关联数据源的内容创建了3种Web属性。图1.4显示了其中一种Web属性:BBC Wildlife Finder

在使用关联数据时,BBC摒弃了脑海中传统的内容管理观念。如果BBC的编辑发现某个数据有误,他们通常会在第三方网站(而不是BBC自己的网站)进行修改。编辑们对第三方网站的内容进行加工,以使BBC的网站信息更加准确,同时也让公共知识资源的质量得以提高。当然,BBC的编辑之所以能这样做,是因为他们拥有某些网站(如维基百科)的读写权限。

BBC采用数据网既是一种创新,对听众来说也非常有用。在BBC Programmes开始使用关联数据之前,只有少数几个最受欢迎的广播节目才有Web存在。

通过访问和重用BBC发布的关联数据,其他开发人员也能从中受益。如果用户希望利用从多个网页中收集的信息创建一个新网页,可以使用关联数据提供的标准方式。

关联数据是自描述性的(self-descriptive),具有许多积极的副作用,其中不那么明显的一个是偶发性重用(serendipitous reuse)。关联数据的发布者可能会带着某种目的将数据公之于众,但如何使用这些数据取决于用户。

负责运营维基百科的维基媒体基金会(Wikimedia Foundation)并不清楚BBC希望使用他们的数据。维基百科的志愿者编辑在创建有关倭黑猩猩(bonobo)[10]的词条时,也没有将BBC考虑在内。BBC并未与DBpedia协商要使用后者的数据,创建DBpedia的学者也未曾与维基百科协商过。从某种意义上说,关联数据实现了无协同合作(cooperation without coordination)。

为了在万维网上查找所需的数据,BBC可能使用了传统的全文搜索引擎(如Google),也可能使用了语义搜索引擎(如Sindice[11])。一旦获得所需的信息,关联数据就能在一定程度上简化开发团队的工作。

无论何种规模的企业和组织,都能利用关联数据强化自己的内容、集成其他网站的数据并支持他人重用自己的数据。后面的章节将对此进行讨论。

1.4 关联数据原则

关联数据使用RDF数据模型并遵循与RDF相关的其他标准,如同使用HTTP一样。尽管关联数据以RDF为基础构建,但并不等同于RDF。关联数据遵循以下4条原则,这是它有别于RDF之处。

  • 使用URI命名事物。
  • 使用HTTP URI以便于用户查找事物名称。
  • 当用户查找URI时,通过RDF*[12]、SPARQL等标准提供有用的信息。
  • 包含指向其他URI的链接,以便于用户发现更多的内容。

注意

 

万维网之父、关联开放数据项目的先驱Tim Berners-Lee提出了上述4条关联数据原则。如果希望深入了解他的思想,可以阅读他在2006年发表的Linked Data一文[13]

接下来,我们按顺序讨论这4条原则。

1.4.1 第1原则:使用URI命名事物

关联数据第1原则旨在处理事物的标识。因为如果无法标识事物,其他一切都无从谈起。读者或许对标识事物所用的底层技术已有所了解,它的全名为通用资源标识符(Universal Resource Identifier,URI)。URI用于在关联数据中命名事物,它是URL(统一资源定位符)的一种广义形式,而URL的作用是在浏览器中查找网页。换言之,所有URL都是URI,反之则不成立。URI是一种通用的唯一名称,而URL是在万维网上解析网页的一种特殊类型的URI。

读者对HTTP URL肯定不会感到陌生,它是万维网上最常见的URL类型。在浏览器的地址栏中输入某个URL,就能跳转到相应的页面。浏览器也可以处理其他类型的URL。例如,FTP(文件传输协议),其URL以ftp://开头,而file: URL用于访问保存在本地磁盘上的文件。

URL可以无歧义地定位网页所在的位置,同一个URL指向的是同一份文档。与之类似,关联数据利用URI来无歧义地命名事物。

注意

 

在阅读URI规范(RFC 3986[14])时,读者可能好奇文档为何将URI称为“Uniform Resource Identifier(统一资源标识符)”,而不是“Universal Resources Identifier(通用资源标识符)”。这是一个历史遗留问题,感兴趣的读者可以参考Tim Berners-Lee于1998年发表的设计文档Web Architecture from 50,000 feet[15]

总而言之,为了讨论事物,首先必须能标识它们,URI的作用就是在关联数据中标识事物。“事物”既可以是具象的(如图书、人或基因),也可以是抽象的(如爱情或战争),还可以是其他形式的数据表示(如CSV文件中的某一行或关系数据中的表)。

实际上,确实存在指向“爱情”和“战争”的URL。DBpedia项目修改了维基百科条目的URL,创建了描述这两个概念的页面[16]。单击页面底部的链接,将跳转到相应的维基百科词条,后者包含描述“爱情”和“战争”的链接数据。

1.4.2 第2原则:使用HTTP URI以便于用户查找事物名称

能在世界范围内没有歧义地讨论事物固然可喜,不过我们也可以采用其他标识方式来命名事物。例如,一般通过国际标准书号(ISBN)对图书进行标识。以英国作家Charles Dickens的长篇小说The Old Curiosity Shop为例,其ISBN是0140437428。我们可以创建一个类似于isbn:0140437428这样的URI,然后将其复制到浏览器并观察结果。不过,浏览器无法处理这样的URI,因为它并非标准的URI格式。这就是关联数据第2原则所处理的问题。HTTP URI可以在万维网上解析,也可能无法解析。

1.4.3 第3原则:在用户查找URI时提供有用的信息

我们可以在Web浏览器中输入任何HTTP URI,由浏览器负责处理。浏览器通过解析URI来查找所用的主机和端口号,并尝试建立HTTP连接。浏览器请求由URI的路径部分所标识的资源。如果远程服务器通过返回某个资源表示(如网页)来肯定地作出响应,则这个URI也是URL,它在万维网上是可以解析的。根据关联数据第3原则,应尽量保证标识符可以在万维网上解析。创建一个用于命名事物的URI时,应让它指向现有的Web资源或用户自己构建的资源。无论哪种情况,我们都希望URI能解析为指向命名事物的有用描述。

我们以位于爱尔兰的戈尔韦机场(Galway Airport)为例进行讨论。清单1.1列出了该机场在DBpedia中的URI[17]。在Web浏览器中输入该URI,浏览器将重定向到一个描述戈尔韦机场且人类可读的RDF文档。滑动到页面底部并单击指向维基百科的链接[18],将跳转到相应的维基百科词条。后者包含和DBpedia相同的信息,但页面布局效果更好。

清单1.1 图1.6所示电子表格的示例模式(Turtle格式)

@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix dc: <http://purl.org/dc/terms/> .
@prefix loc: <http://www.daml.org/2001/10/html/airport-ont#> .
@prefix eg: <http://example.com/> .
@prefix qb: <http://purl.org/linked-data/cube#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
@prefix sdmxa: <http://purl.org/linked-data/sdmx/2009/attribute#> .
@prefix sdmx-measure: <http://purl.org/linked-data/sdmx/2009/measure#> .     ←---前缀信息(用于缩写较长的URI)
<http://example.com/my_temperature_data>           ←---电子表格的URL
  rdfs:label "Temperature observations";                     ←---符合人类阅读习惯的短标记
  rdfs:comment "Temperature observations at Galway Airport";     ←---符合人类阅读习惯的较长注释(用于描述资源)
  loc:location <http://dbpedia.org/resource/Galway_Airport>;    ←---位置(戈尔韦机场)
  dc:creator "Michael Hausenblas".            ←---作者或创建者的姓名
eg:day a rdf:Property, qb:MeasureProperty;     ←---“day”的精确定义
  rdfs:label "day"@en;
  rdfs:subPropertyOf sdmx-measure:obsValue;
  sdmxa:unitMeasure <http://dbpedia.org/resource/Day> ;
  rdfs:range xsd:date .

eg:temperature a rdf:Property, qb:MeasureProperty;         ←---“temperature”的精确定义
  rdfs:label "temperature"@en;
  rdfs:subPropertyOf sdmx-measure:obsValue;
  sdmxa:unitMeasure <http://dbpedia.org/resource/Celsius> ;
  rdfs:range xsd:decimal .

DBpedia项目将维基百科中的结构化数据转换为RDF,后面的章节将讨论如何访问RDF。我们暂时采用HTTP URI来命名机场,它解析为机场所在位置的可读描述。

1.4.4 第4原则:包含指向其他URI的链接

关联数据为什么是“关联”的?如果包含指向相关信息的超链接,网页将更为有用。与之类似,如果链接到相关数据、文档和描述,数据也将更为有用。关联数据第4原则明确了这一概念:当用户数据链接到相关资源时,它就成为关联数据。如果用户采用可解析的HTTP URI来发布数据,则其他用户也可以链接到这些数据。循着这些链接,我们能有效利用数据网,如同在文档网(Web of Documents)上尽情冲浪一样。

清单1.1显示了第4原则在实际中的应用。该清单包括指向描述戈尔韦机场的DBpedia页面的链接和天数的度量单位。

1.5 关联开放数据(LOD)项目

本书使用的大部分数据都可以从万维网上免费获取。一个神奇之处在于,百科全书和词典、政务统计数据、生化收集品和濒危物种信息、书目数据、音乐艺术家及其歌曲信息、学术研究论文等各种开放内容项目都使用相同的数据格式,可以通过相同的API获取。这一切都是因为关联开放数据(Linked Open Data,LOD)项目。

LOD项目[19]始于2007年,是一个由W3C语义网教育和拓展兴趣组(Semantic Web Education and Outreach Interest Group)[20]发起的社区性活动,旨在“为所有人提供免费的数据”。

万维网上发布的关联数据集合称为LOD云(LOD cloud)。最近一次将LOD云可视化的尝试如图1.5所示。

注意

 

发音时,一般将“LOD”的每个字母读出来:“ell oh dee”。

以下是有关LOD云的一些信息。

  • 从2007年起,LOD云的规模每隔10个月就会增长一倍。截至本书写作时,LOD云已拥有超过300个来自各个领域的数据集[21],这些数据全部向开发人员开放使用。
  • 截至2011年年底,LOD云拥有超过295个来自地理、媒体、政府、生命科学等各个领域的数据集。整个LOD云包含超过310亿个数据项以及这些数据之间的大约5亿个链接。
  • 由于LOD云的规模过于庞大,2012年没有进行将其可视化的尝试。
  • 在LOD云中,超过40%的关联数据由政府(主要来自英国和美国)提供,其次是地理数据(22%)和生命科学数据(约10%)。
  • 生命科学(包括一些大型制药企业)贡献了数据集之间超过50%的链接。来自出版领域(如图书、期刊)的数据贡献了19%的链接,来自媒体领域(如BBC、《纽约时报》)的数据贡献了12%的链接。
  • 在LOD云中,原始数据所有者发布的数据占总量的 33%,第三方发布的数据占总量的67%。例如,许多大学采用关联数据格式重新发布政务数据,并在此过程中对数据描述进行调整。

..\17-1007 图\0105.tif

图1.5 2011年年底的LOD云。圆圈表示可以免费使用的数据集,箭头表示数据集之间的链接

1.6 数据描述

LOD云并非数据孤岛的集合。关联数据提供了关系数据库或内容管理系统所不具备的一种特性:可发现性(discoverability)。假设客户为我们提供了一个包含某些数据的电子表格,为了在应用程序中使用这些数据,我们需要了解每一列的含义。一般来说,可以通过查看列标题了解相关信息,如图1.6所示。

..\17-1007 改图\0106.tif

图1.6 某电子表格中的Web数据示例,描述了一段时期内的温度

图1.6所示的数据存在一定问题:如果创建者没有提供进一步的信息,我们就无法了解数据的真正含义。

我们可以给客户打电话询问温度是否采用摄氏度,或根据温度值的范围进行猜测。不过大部分情况下,我们难以获得所需的信息,这些信息要么丢失,要么找不到创建者。描述性的列标题虽然有一定帮助,但仍然无法提供所需的全部信息,比如数据采集地和数据采集者。相比之下,图1.7所示的模式信息(schema information)更为实用。

..\17-1007 图\0107.tif

图1.7 图1.6所示数据的模式信息示例

图1.6指出了大部分电子表格数据存在的一个问题,即缺乏理解数据所需的上下文环境。图1.7通过注释解决了这个问题,注释可以提供足够的背景信息,有助于新用户了解数据创建者的意图。

关联数据不仅能为电子表格提供必要的模式信息,也支持采用开放和可扩展的格式发布数据本身。关联数据还提供了一种明确的方式,帮助用户链接到万维网上任何位置的相关数据。可参引标识符(dereferenceable identifier)和网址用于模式信息和数据资源,网址用于获取模式文档和相关数据。用户只需循着链接而行,就能找到所需的信息。这就是可发现性在实际中的应用。

如果遵循以下万维网规则,就能更好地使用关联数据:采用HTTP URI命名数据元素,这些URI可以被解析,从而发现更多的相关信息。重要且值得反复强调的一点是,关联数据应包含指向万维网上其他信息的链接。我们已在1.4节详细讨论了关联数据的4条原则。

关联数据原则为万维网上的数据提供了一种通用的API。较之由Flickr、Twitter、Amazon等主要网站发布的独立(且设计不同的)API,这种API能为开发人员提供更多的方便。

清单1.1显示了如何利用关联数据为图1.6所示的电子表格数据创建模式。无需担心,这段代码其实非常简单,我们将解释如何创建并读取模式。熟悉之后就会发现,它比XML或其他用户的代码更容易理解,我们只需遵循一些简单的规则即可。

除非确有必要,否则读者无需逐字逐句地研究清单1.1的内容。我们采用一种简单的方式(以文件的形式或保存在数据库中,两种方式都可以通过SPARQL查询语言进行查询)展示关联数据及其发布方式。

接下来,我们对代码进行深入讨论。前面曾经提到过,关联数据使用RDF作为数据模型。单条RDF陈述(statement)描述了两个事物以及它们之间的关系。严格来说,应该将其称为实体-属性-值(Entity-Attribute-Value,EAV)数据模型。不过在关联数据中,通常将陈述中的 3 个元素称为主体(subject)、谓词(predicate)、客体(object),三者与实体、属性、值一一对应。例如,本书名为《关联数据:万维网上的结构化数据》,我们可以通过本书的URI、定义书名属性的已知关系、书名的字面量字符串等3个元素将其转换为RDF,其过程如图1.8所示。

..\17-1007 图\0108.tif

图1.8 RDF陈述示例

实体(或主体)可以是任何由URI命名的事物,比如一个人、一本书、一辆车或一个网页。在本例中,主体是唯一标识本书的URI。实体的属性(或谓词)将主体和另一个实体联系起来,或描述实体本身的信息(我们称之为主体的属性)。在本例中,我们采用书名的关系作为谓词,书名作为客体。关系和属性是RDF陈述的客体。藉由这种标准化的数据模型,我们创建了一个对所有关联数据源一致的API。换言之,用户在掌握关联数据模型之后,就能使用任何遵循该模型的数据源。用户可以随时在Web浏览器中输入某个谓词的URI,以查看它的含义。

下面这条从清单1.1中提取的陈述是一个简单的“三元组(triple)”,也称为RDF陈述:

<http://example.com/my_temperature_data> rdfs:label "Temperature observations";

其中,<http://example.com/my_temperature_data>是一个URI,它表示并可能指向示例电子表格,它构成了RDF陈述的实体(主体)。rdfs:label "Temperature observations";中的两个组件分别是RDF陈述的属性(谓词)和值[22](客体)。在本例中,我们为电子表格添加了一个人类可读的标记"Temperature observations"

rdfs:comment "Temperature observations at Galway Airport";为同一主体提供了另一个属性,它构成了另一条RDF陈述。我们可以继续为电子表格添加相关信息,直到完成为止。

RDF并未对可以链接或描述的内容作任何限制,这是RDF之所以成为一种描述资源的框架的原因。RDF陈述往往会创建元数据的图谱,也就是说,它们不需要构成层次关系。有鉴于此,读者将经常接触到RDF图谱(RDF graph)这个术语。

1.7 RDF:关联数据所用的数据模型

关联数据是一种结构化数据。更准确地说,这里讨论的结构化数据基于由W3C[23]定义的RDF数据模型。根据惯例,我们采用HTTP URI标识事物,然后在解析HTTP URI时提供事物的相关信息。

与“普通”的万维网(我们倾向于将文档网从数据网中剥离出来)类似,解析HTTP URI通常意味着对其执行HTTP GET请求,后者是客户端使用HTTP所能执行的最简单的操作。GET请求由客户端发送给服务器,要求后者返回任何收到的URI。我们可以采用Web浏览器或命令行Web客户端工具(如cURL[24],它是“Client for URLs”的缩写)执行上述操作。DBpedia中采用HTML格式显示“倭黑猩猩”词条[25],后者基于维基百科的同一词条。通过将DBpedia链接中的“page”改为“data”并添加合适的文件扩展名,用户可以下载有关倭黑猩猩的关联数据:

$ curl -L http://dbpedia.org/data/Bonobo.n3

在本例中,.n3是用于关联数据的一种文件扩展名。URI的发布者有权根据自己的喜好创建URI,只需遵守HTTP规范中有关合法字符的规定即可。在前面所示的代码段中,DBpedia采用dbpedia.org作为自己的服务器名称,输入“www.dbpedia.org”将重定向到DBpedia的主页dbpedia.org。DBpedia将所有HTML条目置于page/path下,并为每个条目分配在维基百科中使用的相同标识符(如本例中的“Bonobo”)。DBpedia还选择了某种约定以构建其关联数据URL。

curl命令表示“解析URI,并将服务器返回的任何信息以标准方式输出(-L表示遵循遇到的任何HTTP重定向)”。在控制台执行该命令时,将在名为N3的序列化中打印描述倭黑猩猩的RDF数据。这是因为所给定的URI标识了倭黑猩猩的概念,当解析该URI时,我们希望返回关于倭黑猩猩的关联数据描述。

本书涉及大量关联数据,几乎所有关联数据都采用Turtle格式。Turtle是表示RDF数据模型的最简语法,旨在提供易于阅读的关联数据。由于Turtle是N3的一个子集,因此DBpedia选择使用.n3作为两种格式的文件扩展名。第2章将详细讨论RDF数据格式。

由于整个数据转储过于庞大,本书不对此作深入介绍。不过读者可以从清单1.2显示的摘要中窥知一二。请注意,由于执行给定curl命令后所返回的数据量较大,读者可能需要在其中找到本例所示的代码。

清单1.2 关于倭黑猩猩的关联数据摘录(Turtle格式)

@prefix dbpedia:        <http://dbpedia.org/resource/> .
@prefix dbpedia-owl:    <http://dbpedia.org/ontology/> .
@prefix foaf:           <http://xmlns.com/foaf/0.1/> .

dbpedia:Bonobo     rdf:type    dbpedia-owl:Eukaryote ,
                   dbpedia-owl:Mammal ,
                   dbpedia-owl:Animal .

dbpedia:Bonobo     foaf:name     "Bonobo"@en ;      ←---  动物的英文名称(倭黑猩猩名为Bonobo)
                   foaf:depiction <http://upload.wikimedia.org/wikipedia/
     commons/a/a6/Bonobo-04.jpg> ;

如果读者熟悉键—值结构化数据(可以在配置文件中找到),或许已经猜到上述代码的作用。

清单1.2中包括一个名为dbpedia:Bonobo的元素,它有一个英文名(bonobo)、一张来自Wikimedia.org的图片链接(depiction)以及若干类型:动物(Animal)、哺乳动物(Mammal)和真核生物(Eukaryote)。

在清单1.2中,前3行的前缀旨在缩短URI以方便阅读。

另一种表示该RDF数据段的方法是采用图表形式,如图1.9所示。RDF既支持字面值(如动物名称),也支持指向另一个事物的链接(如图片)。

这一节讨论的核心问题很简单:在查找某个关联数据资源的HTTP URI时,我们希望获取以某种RDF序列化格式表示的结构化数据。由于Turtle格式易于阅读,本书将采用这种RDF序列化格式表示数据。

..\17-1007 改图\0109.tif

图1.9 关于倭黑猩猩的关联数据摘录(图表形式)

1.8 关联数据应用程序剖析

前面的章节介绍了关联数据的4条原则,并对RDF进行了初步讨论。接下来,我们将探讨关联数据应用程序。我们将对万维网上一个现有的关联数据应用程序进行剖析,并讨论HTTP端点、HTML源代码、相关联的JavaScript等可公开访问的信息。

这个应用程序是美国国家环保局(U.S. Environmental Protection Agency,EPA)的关联数据服务。截至本书写作时,EPA已发布了全美大约290万个设施以及10万种化学物质的数据作为关联数据。约有1%的设施提交了超过25年的年度污染评估,这些信息也可作为关联数据。图 1.10显示了一个典型设施的页面[26],该设施是位于美国阿拉巴马州迪凯特(Decatur)附近的Browns Ferry核电站。

注意

 

在2015年时,这一节讨论的关联数据应用程序经过了质量控制测试。EPA关联数据网站的部分内容已被复制到LinkedDataDeveloper.com,以便用户了解其创建过程。

首先需要注意的是,底层数据来自多个不同的系统。维基百科收集了Browns Ferry核电站等许多大型设施的图片和摘要信息,EPA自己并不保存这些信息。该页面还包括核电站的一般信息,如通信地址和生成的污染报告。通信地址和污染信息保存在不同的EPA数据库中,且无法互通。关联数据作为一种通用的数据语言(lingua franca),能促进信息之间的整合。

..\17-1007 改图\0110.tif

图1.10 美国国家环保局(EPA)发布的关联数据应用程序,页面显示了位于阿拉巴马州迪凯特附近的Browns Ferry核电站的信息。所用的数据来自不同的数据源

1.8.1 获取设施的关联数据

接下来,请读者单击核电站页面右上方Linked Data模块中的3个链接。三者均指向创建页面所用的数据,每个链接使用不同的关联数据格式。

第1个链接标记为Describe Data,单击后将跳转到原始数据的HTML视图。后者虽然美观,但并非标准的关联数据机制,因此可不予考虑。第1个链接的信息来自一个Callimachus关联数据服务器,后者将在第9章的示例中使用。第2个和第3个链接分别指向访问底层关联数据的两种常用标准格式:RDF/XML和Turtle。毫无疑问,RDF/XML是一种XML格式,而Turtle是一种相当简洁的语法,更便于用户阅读。

观察Browns Ferry核电站页面的HTML源代码,可以看到关联数据的访问方式。清单1.3显示了相关的HTML代码,清单1.4显示了JavaScript的单击函数处理程序。

清单1.3 图1.10所示的关联数据元素的HTML代码

<h3>Linked Data</h3>
<ul>
    <li><a href="?describe">Describe Data</a></li>                ←---链接到“Describe Data”函数
    <li><a href="#" id="rdfxml">View Data as RDF/XML</a></li>            ←---链接到RDF/XML单击函数处理程序
    <li><a href="#" id="turtle">View Data as Turtle</a></li>         ←-链接到Turtle单击函数处理程序
--
</ul>

清单1.4 清单1.3所示的HTML元素的JavaScript点击函数处理程序

jQuery(function($) {
    $('#rdfxml').click(function(event) {
        event.preventDefault();
        var request = $.ajax({
          url: '?describe',
          headers: { Accept : "application/rdf+xml" }       ←---为RDF/XMF格式设置HTTP请求标头
        });

        request.done(function() {
            var win = window.open('', document.URL);
            win.document.write('<pre>\n' + request.responseText.replace(/</g,
➥ '&lt;').replace(/>/g, '&gt;') + '\n</pre>');
        });

        request.fail(function() {
            alert("We're sorry, the request could not be completed at this
➥ time. Please try again shortly.");
        });
    });
$("#turtle").click(function(event) {
    event.preventDefault();
    var request = $.ajax({
        url: '?describe',
    headers: { Accept : "text/turtle" }        ←---为Turtle格式设置HTTP请求标头
    });

    request.done(function() {
        var win = window.open('', document.URL);
        win.document.write('<pre>\n' + request.responseText.replace(/</g,
➥ '&lt;').replace(/>/g, '&gt;') + '\n</pre>');
    });

    request.fail(function() {
        alert("We're sorry, the request could not be completed at this
➥ time. Please try again shortly.");
    });
});
});

仔细观察清单1.4的程序不难发现,可以使用同一个URL来访问Browns Ferry核电站页面的关联数据。这个URL与渲染页面的默认HTML的URL几乎相同(注意代码中添加的HTTP查询字符串?describe),且与特定服务器的实现细节有关。URL构造的细节并不重要,因为不同网站的URL可能有所不同。

3个请求使用了不同的HTTP Accept标头:

  • HTML:使用Accept: text/html
  • RDF/XML:使用Accept: application/rdf+xml
  • Turtle:使用Accept: text/turtle

Accept标头用于通知服务器Web客户端可以接收的格式类型。这就是所谓的HTTP内容协商(content negotiation),也称为conneg。并非所有的关联数据网站都通过内容协商支持数据访问,但相当一部分网站是这样处理的。

内容协商允许用户直接请求数据,而不是依靠网页作者来创建链接。通过对URL执行HTTP GET操作并使用Turtle的Accept标头,可以获得Browns Ferry核电站页面的关联数据(Turtle格式):

$ curl –L -H 'Accept: text/turtle'
➥ http://linkeddatadeveloper.com/facilities/110000589355?describe

能否获得创建网页所需的底层数据,是关联数据应用程序区别于其他应用的一个标志。大部分关联数据应用程序都会公开数据以供进一步重用。关联数据网站的用户如果不喜欢现有的信息展示方式,也可以抓取并创建自己的数据,甚至将数据与其他网站或应用程序的数据进行合并,以构建更为复杂的应用。关联数据将数据从应用程序的UI中释放出来。

1.8.2 通过关联数据创建UI

可以说,Browns Ferry核电站页面是完全基于关联数据构建的,仅用少量关联数据就能证明这一点。接下来,我们观察如何创建UI。清单1.5显示了摘录的部分关联数据,包括用于创建地图、显示核电站图片、显示获取街道地址URI的信息。需要再次强调的是,由于执行给定curl命令后所返回的数据量较大,读者可能需要在其中找寻本例所示的代码。

清单1.5 Browns Ferry核电站关联数据摘录

@prefix foaf: <http://xmlns.com/foaf/0.1/> .
@prefix place: <http://purl.org/ontology/places#> .
@prefix vcard: <http://www.w3.org/2006/vcard/ns#> .

<http://linkeddatadeveloper.com/facilities/110000589355> place:point_on_map
➥ "34.710917,-87.112"^^place:latlong ;                                         ←---设施的经纬度
foaf:depiction                                                   ←---维基共享资源中设施图片的URI
<http://upload.wikimedia.org/wikipedia/commons/a/ab/Browns_ferry_NPP.jpg> ;
vcard:adr                                              ←---     街道地址的URI
<http://linkeddatadeveloper.com/addresses/
➥ shawrdatnuclearplantrdathensal35611usa> .

Browns Ferry核电站页面采用OpenStreetMap(OSM)[27]绘制地图。OpenStreetMap API使用经纬度来创建某个点的地图。由于关联数据中包括经纬度信息,这使得调用OpenStreetMap API变得很容易。

此外,关联数据也提供了所需图片的URL,因此不难在页面中插入图片。只要在src属性中添加使用该URL的HTML image标记,就能很容易地插入图片。

一个有趣的问题是,如何显示核电站的地址?从地图中可以看到,核电站位于Shaw Road和Nuclear Plant Road交界处,不过关联数据只提供了街道地址的URL。那么,怎样才能获得详细的地址信息呢?答案很简单,解析地址的URL即可。执行以下命令:

$ curl –L -H 'Accept: text/turtle' http://linkeddatadeveloper.com/addresses/
     shawrdatnuclearplantrdathensal35611usa

解析地址URL将返回和该地址有关的所有数据,包括尚未在UI中使用的数据。这是使用关联数据的又一佐证:我们通常可以获得比特定接口所用数据更多的数据。较之其他结构化数据技术,关联数据能更方便地查找和使用额外的信息。

清单1.6显示了完整的街道地址信息。请注意,地址包括县名(Limestone)、国家名(USA)以及其他我们之前所不了解的信息。

清单1.6 Browns Ferry核电站街道地址的关联数据

@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix foaf: <http://xmlns.com/foaf/0.1/> .
@prefix vcard: <http://www.w3.org/2006/vcard/ns#> .
@prefix frs: <http://linkeddatadeveloper.com/id/us/fed/agency/epa/frs/schema#> .

<http://linkeddatadeveloper.com/addresses/
     shawrdatnuclearplantrdathensal35611usa> a vcard:Address ;
    vcard:street-address "Shaw Rd At Nuclear Plant Rd." ;
    vcard:locality "Athens" ;
    vcard:region "Alabama" ;
    frs:county_name "Limestone" ;                 ←---县名
    frs:fips_county_code "01083" ;
    frs:state_code "AL" ;
    frs:state <http://linkeddatadeveloper.com/states/AL> ;
    vcard:postal-code "35611" ;
    vcard:country-name "USA" ;                        ←---国家名
    foaf:based_near <zip:35611> , <zip:35611> .

接下来,我们讨论如何将关联数据应用程序分发到多个服务器。有不少方法可以将数据和应用程序分段,最简单的一种是使用不那么引人注目的超链接。

Browns Ferry核电站页面右下方的Released模块列出了历年的污染报告。单击名为Lead in 2001的链接,可以看到核电站在2001年提交的铅污染报告。报告的结果页面如图1.11所示。

..\17-1007 图\0111.tif

图1.11 Browns Ferry核电站提交的2001年铅污染报告的HTML渲染

图1.11总结了Browns Ferry核电站在2001年排放的铅污染量。单击页面左上方红圈内的Lead超链接,将跳转到一个描述铅的化学性质和化学名称同义词的页面。化学信息来自完全不同的数据集,由此形成了一个自然的分割点。

这里存在一个微妙且难以发现的问题:和铅有关的页面可以位于任何服务器上。尽管Web超链接并不引人注目,但它能以用户所希望的任何方式对数据和关联数据应用程序进行分段。这些数据和应用既可以位于同一台服务器上,也可以分布在成百上千台服务器上,用户只需链接到合适的位置即可。我们可以直接使用网页中关联数据的超链接,也可以通过关联数据URI构建新的链接对它们进行重定向。所有标准的Web工具和技术都能用于创建关联数据应用程序。

1.9 小结

关联数据是在万维网上发布和使用结构化数据的一系列技术。它以RDF(资源描述框架)作为数据模型,采用RDF序列化格式表达数据。但是,关联数据和RDF并不能划等号。链接在关联数据中扮演了重要角色,关联数据应该(也必须)链接到万维网上的其他关联数据。

关联数据通过HTTP URI标识事物,采用HTTP将事物描述从数据集发送给关联数据用户(如浏览器或应用程序)。

关联数据是一个通用的概念,理论上说,它可以用于描述任何内容。这一章介绍了大型机构在万维网上使用关联数据的一些示例,并讨论了实际关联数据应用程序的组件。此外,关联数据也可以用于私有设置。

采用关联数据开发应用程序并不比采用原生JSON或XML数据源复杂。关联数据的灵活性更强,且无需掌握过多的API。


[1] 参见http://wiki.dbpedia.org/(原链接跳转至此)。DBpedia项目始于2007年,Tim Berners-Lee曾将其称为去中心化关联数据最知名的尝试之一。——译者注

[2] 功能无法互通、信息无法共享的系统,是一种普遍的现象。——译者注

[3] Borders成立于1971年,曾是全美第二大连锁书店。随着Amazon的兴起,消费者对实体书店的兴趣日益减小,导致Borders的财务状况不断恶化。Borders于2011年2月正式申请破产保护。——译者注

[4] 参见Facebook开发者“点赞”按钮插件:https://developers.facebook.com/docs/plugins/like-button(原链接跳转至此)。

[5] 参见Google Webmaster Tools的About rich snippets and structured data(2013年6月5日):https://developers.google.com/search/docs/guides/intro-structured-data(原链接跳转至此)。

[6] 参见http://www.bbc.co.uk/programmes。

[7] 参见http://www.bbc.co.uk/music。

[8] 参见http://www.bbc.co.uk/nature/wildlife。

[9] 参见https://musicbrainz.org/。

[10] 倭黑猩猩与人类共享98.7%的DNA,是与人类关系最密切的灵长类动物。倭黑猩猩在本书中会频繁出现。——译者注

[11] 2014年5月,创始团队宣布停止对Sindice提供支持,Sindice.com目前已无法访问。——译者注

[12] 术语“RDF*”有时用于指代整个RDF标准家族。

[13] 参见https://www.w3.org/DesignIssues/LinkedData.html。

[14] 参见https://tools.ietf.org/html/rfc3986。

[15] 参见https://www.w3.org/DesignIssues/Architecture.html。

[16] 参见http://dbpedia.org/page/Love(“爱情”)和http://dbpedia.org/page/War(“战争”)。

[17] 参见http://dbpedia.org/page/Galway_Airport。

[18] 参见https://en.wikipedia.org/wiki/Galway_Airport。

[19] 参见Linked Data—Connect Distributed Data across the Web:http://linkeddata.org/。

[20] 参见https://www.w3.org/wiki/SweoIG。

[21] 参见http://lod-cloud.net/state/。

[22] 【勘误】原文错误。主体、谓词、客体分别对应实体、属性、值。

[23] 参见https://www.w3.org/。

[24] 通过以下链接下载跨平台命令行Web客户端工具cURL:https://curl.haxx.se/dlwiz/。

[25] 参见http://dbpedia.org/page/Bonobo。

[26] 图1.10的来源参见http://linkeddatadeveloper.com/facilities/110000589355?view。

[27] 参见http://www.openstreetmap.org/。OSM是一个开源地图项目,旨在提供内容自由、所有用户都能编辑的地图服务,有“地图领域的维基百科”之称。——译者注

目录

相关技术