利用语义 Web 技术集成异构数据

将多种格式的数据组合到单个报表中,使用免费工具自动化各种格式到 RDF 的转换

不同的 RDF 数据集比其他常见格式的不同数据集要容易组合得多。您可以轻松地将异构的非 RDF 数据集转换成 RDF,然后再组合起来创建增强的新内容。在本文中,学习如何将电子表格数据、来自 web 服务的 CSV 数据和来自网站的字段数据集成到单个报表中。

Bob DuCharme, 解决方案架构师, TopQuadrant

Bob DuCharme 的照片Bob DuCharme 是 TopQuadrant 的一位解决方案构架师,TopQuadrant 是一家语义 Web 应用程序建模、 开发和部署软件提供商。它撰写了 4 部关于信息及技术的图书,还在网上发表和印刷出版了近百篇相关文章,而在任何这些作品中从未使用过 “功能” 的概念。他的博客地址为:http://www.snee.com/bobdc.blog。



2010 年 10 月 25 日

核心语义 Web 技术就是 RDF,这是一种 W3C 标准,用于将所有数据缩减成三部分的语句,即三元组(triple)。如果您的数据满足三元组数据模型,并存储在一种叫做三元组仓库(triplestore)的专门数据库中,那么语义 Web 技术的优势会很显著。但是这并不表示,数据是更为传统的格式(比如关系数据库和电子表格),这种技术就毫无用处。有开源和商业工具可用于将这些格式的数据转换成三元组,从而让您可以轻松组合多个来源、不同格式的数据。如果您想要在异构源之间交叉引用,或者用另一个源的数据增强某个源的数据,那么到三元组的临时转换是进行特定数据集成的优秀方式。

常用缩略词

  • CSV:逗号分隔的值
  • HTML:超文本标记语言
  • RDF:资源描述框架
  • SPARQL:SPARQL 协议和 RDF 查询语言
  • URI:统一资源标识符
  • URL:统一资源定位符
  • W3C:万维网联盟
  • XML:可扩展标记语言
  • XSLT:可扩展样式表语言转换

随着越来越多的数据变得作为 Linked Data(参见 参考资料)公共可用,您可以使用这些数据来增强本地存储的数据,使之意义更丰富,也更有趣。作为一个例子,本文展示如何用公共可用的关于所列公司的数据来增强(虚假的)分析师买入/卖出/持有推荐的 Excel® 电子表格,做出一个更具吸引力、富有信息的报表。此应用程序的输入、输出和脚本都使用免费软件,可供 下载

处理三元组

三元组的三个部分被正式称为主语(subject)谓语(predicate)宾语(object)。如果您来自比较传统的数据库背景,可能会把它们看作资源标识符、属性名称和属性值。例如,如果一个关系数据库或电子表格说雇员 94321 的雇佣日期是 2007-10-14,那么很容易表达为三元组。

三元组的主语和谓语必须表达为 URI,以便彻底明确,并且利用流行领域做这件事情的标准模式和最佳实践变得越来越成熟。由惟一标识符提供的额外上下文表示,指定三元组集合中数据结构的模式是可选的,尽管它对于添加可启用推理和约束检查的元数据很有用。当您认为组合多个关系数据集或 XML 数据集最困难的环节是链接它们模式的对应部分时,您可以看到,由于不需要 RDF 模式,使得组合多个 RDF 数据集更为简单 — 通常简单到只是连接文件。

要通过抽取数据子集、排序并重新排列数据而实现应用程序逻辑,关系数据库具有 SQL,XML 具有 XSLT 和 XQuery。RDF 具有用于查询三元组的对应 W3C SPARQL 标准,在您组合了一些三元组集合之后,此标准将尤其方便,正如您在本文中将会看到的一样。

输入简单的电子表格,输出优美的报表

图 1 展示了 analystRecs.xls Excel 文件(参见 下载)的前几行:

图 1. 用作输入数据的 Excel 电子表格的前几行
analystRecs.xls 中前三行数据的屏幕截图

图 1 中的每一行数据由以下部分组成:

  • 一个虚假的分析师姓名
  • 一家公司的股票代号
  • 公司名称
  • 该公司股票的一个(随机的)买入/卖出/持有推荐
  • 推荐的日期和时间
  • 公司的分析通常由传统上由出版商用于测试布局外观的 "lorem ipsum" 文本组成

图 2 展示了电子表格中列出的第三家公司 (IBM) 的增强版本,正如它出现在最终报表中一样:

图 2. 最终报表的 IBM 数据增强版本
增强的 IBM 数据的屏幕截图,正如它出现在最终报表中一样

除了来自 Excel 文件的推荐、分析师姓名、公司分析和推荐日期之外,图 2 还包含报表生成脚本运行时的当前股票价格、去年的一些财务数据,以及公司的描述。股价数据来自免费的 finance.yahoo.com web 服务(它将数据返回为 CSV),而 2009 年的数据和公司描述来自 Wikipedia。

图 3 展示了从这些输入创建报表的应用程序的一般架构:

图 3. 应用程序的架构图
应用程序的架构图

图 3 所示:

  1. 来自电子表格、Yahoo! web 服务和 Wikipedia 的数据被转换成 RDF。
  2. RDF 数据被 SPARQL 引擎分类、交叉引用和转换成 XML。
  3. XSLT 引擎将 XML 转换成 HTML 以产生最终的报表。

我使用了免费软件来实现这整个架构,用一个 10 行的(不计算空白和注释)批文件 build.bat 驱动整个过程。您也可以用商业工具(比如 TopQuadrant 的 TopBraid Composer)实现与此相同的架构,工具可以自动化几个开发步骤,从而需要更少的编码。但是比特定实现更为重要的是,您现在可以从日益增长的工具队伍中选择工具,为灵活而特别的、使用语义 Web 数据标准的数据集成实现架构。


转换数据

艰难地从 Excel 到 RDF

很多免费工具和商业产品的特性可以将电子表格转换成 RDF。但是现有的免费工具很复杂,因为它们试图处理大量的电子表格布局。它们的文档化做得很差,因为它们通常是学院项目,所以难以使用。另外,对于免费工具,“读取电子表格”通常意味着读取从电子表格程序导出的 CSV 文件,而不是读取实际的二进制电子表格文件。

我选择使用 Python 将 Excel 数据转换成 RDF。免费的 Lingfo Python 库完成了读取二进制 Excel 文件这项困难的工作,所以我只费很少的精力编写了一个简短的 Python 脚本,为读入的每个单元格产生 RDF 三元组。

finance.yahoo.com 网站提供一个 web 服务,当您使用正确的 URL 时,它会返回当前股票数据的逗号分隔列表。例如,以下 URL 检索关于 IBM、Nokia 和 Honda 的数据:

http://download.finance.yahoo.com/d/quotes.csv?f=sl1d1t1ohgv&e=.csv&s=IBM,NOK,HMC

返回的数据为每个所请求的公司具有一行,具有由请求数据的 URL 中的 f= 参数指定的数据字段。

由于 web 服务完成了检索股票数据并存储在一个简单的数据结构中,所以我只需要将数据转换成 RDF。Perl 的内置 split() 函数使得分割分隔的文本很容易,所以我编写了一个简短的 Perl 脚本 yahooCSV2RDF.pl 来做这件事情。(我本应该使用 Python 来完成 CSV 到 RDF 的转换,但是我之前已经用 Perl 编写了太多类似的脚本,所以我知道能够很快翻版成这个 Perl 脚本。)该脚本的很大一部分逻辑是将日期和时间字段,比如 7/22/20104:00pm,组合成一种更加顺应 ISO 8601 的格式,比如 2010-07-22T16:00:00,这样的格式更容易在其他系统中分类和重用。

Wikipedia 数据的转换不需要我的额外工作。DBpedia 项目已经从您在 Wikipedia 页面右侧灰色矩形框中经常会看到的字段“信息框”数据创建并存储了 10 亿多个三元组。例如,如果查看 Nokia 的 Wikipedia 页面 (http://en.wikipedia.org/wiki/Nokia),您会看到信息框;如果查看 Nokia 的 DBpedia 页面 (http://dbpedia.org/page/Nokia),您会看到 Nokia 的信息框信息和更多信息,可以用 SPARQL 查询语言进行查询。

DBpedia 的网站包含一个页面,您可以在那里输入关于数据的 SPARQL 查询 (http://dbpedia.org/snorql/)。在那里输入以下查询,请求关于 Vodafone 的所有 DBpedia 三元组:

CONSTRUCT { <http://dbpedia.org/resource/Vodafone> ?p ?o } 
WHERE { <http://dbpedia.org/resource/Vodafone> ?p ?o }

如果您将该查询存储在一个 URI 中(在做了适当的字符转义之后。字符转义是大多数编程语言中的一个函数调用),那么对于任何可以发送 URI 并检索结果的程序,您都可以使用该 URI 来检索 Vodafone 三元组。开源的 cURL 工具就是这样一个程序。例如,如果您在 Windows® 或 Linux® 命令行输入以下命令,那么 cURL 会下载 Google 首页的一份副本,并存储在 googleHomepage.html 文件中:

curl http://www.google.com > googleHomepage.html

您可以从由批文件或 shell 脚本驱动的应用程序调用 cURL。要从 DBpedia 检索公司数据,build.bat 调用另一个批文件 getDbpediaData.bat,该文件中的每一行都调用 cURL 来检索特定公司的数据。作为参数提供给每个调用的 URL 包含 SPARQL CONSTRUCT 查询的一个已转义版本,类似于上面的那个查询。


组合和查询数据

收集了所有数据的 RDF 版本之后,我使用另一个 SPARQL 查询(参见 清单 1)来为最终的报表抽取数据:

清单 1. 为最终报表抽取数据的 SPARQL 查询
# PickDataForReport.spq: select data from the combination of RDF sources
# used to create the fake analyst report. Bob DuCharme 2010 no warrantee
# expressed or implied.
PREFIX fn: <http://www.w3.org/2005/xpath-functions#>
PREFIX xs: <http://www.w3.org/2001/XMLSchema#>
PREFIX ar: <http://www.snee.com/ns/analystRatings#>
PREFIX sq: <http://www.rdfdata.org/2009/12/stockquotes#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX foaf: <http://xmlns.com/foaf/0.1/>

SELECT ?tickerSymbol ?coName ?analyst ?description ?recommendation 
  ?recDateTime ?lastPrice ?quoteDateTime ?dayHigh ?dayLow ?openingPrice 
  ?volume ?revenue ?netIncome ?abstract
WHERE {
    ?analystData ar:analyst ?analyst ;
                 ar:company ?coName;
                 ar:description ?description ;
                 ar:tickersymbol ?tickerSymbol ;
                 ar:recommendation ?recommendation ;
                 ar:date-time ?recDateTime .

    ?quoteData sq:tickerSymbol ?tickerSymbol ;
               sq:lastPrice ?lastPrice ;
               sq:dateTime ?quoteDateTime ;
               sq:dayHigh ?dayHigh ;
               sq:dayLow ?dayLow ;
               sq:lastPrice ?lastPrice ;
               sq:openingPrice ?openingPrice ;
               sq:volume ?volume .

    # Next line is why we added language tags to coName: so we
    # could compare it to ?dbURI rdfs:label properly.
    ?dbpURI rdfs:label ?coName . 
    ?dbpURI <http://dbpedia.org/ontology/revenue> ?revenue .
    OPTIONAL {
        ?dbpURI <http://dbpedia.org/ontology/netIncome> ?netIncome .
    } .
    OPTIONAL {
        ?dbpURI <http://dbpedia.org/ontology/abstract> ?abstract .
        FILTER (lang(?abstract) = "en") .
    } .
}

这个 SPARQL 查询包含一些逻辑用于识别来自各个文件的哪些数据组合到一起,但是这也相当简单。如果说查询看起来有点长,那只是因为它列出了很多要从中抽取数据的字段。

要运行这个本地 SPARQL 查询,我使用 arq 命令行工具,它是开源的基于 Java™ 的 Jena 框架(参见 参考资料)的一部分。调用 arq 的 build.bat 行为每个调用提供三种信息:

  • 输入数据的源(本例中是多个源)
  • SPARQL 查询运行的文件的名称
  • 一个指示表明我想要结果为 SPARQL Query Results XML Format

结果保持到文件 reportData.xml 中。

命令使用 --data 开关来告诉 arq,哪个数据用作输入。尽管 图 3 中的架构图展示了来自三个源的数据组合到一起,但是我不需要使用特殊的工具来组合它们。批文件只将 4 个这样的 --data 参数添加到调用 arq 的命令行(第四个是应用程序为容易交叉引用而创建的公司名称文件)。清单 2 展示了批文件的这一行,由于版面原因,这里拆成了三行,当用各种参数调用 Java 程序时,结果被重定向到 reportData.xml 文件:

清单 2. arq 命令指定数据源、SPARQL 查询的位置和结果格式
java -cp %CP% arq.arq --results=XML --query=PickDataForReport.spq 
  --data=analystRecs.rdf --data=coNamesWithLangTags.n3 --data=quoteData.rdf 
  --data=dbpedia.n3 > reportData.xml

何谓 SPARQL Query Results XML Format?大多数 SPARQL 讨论关注的是查询语言和其名称中的 Q 和 P 所代表的协议。Query Results XML Format 是一个单独的规范,用于定义 SPARQL 查询处理程序返回数据的 XML 结构(参见 参考资料)。这种格式足够直观,可由一个相对简单的 XSLT 电子表格处理,这将我带到批文件的最后一步:创建最终的 HTML 报表。


产生报表

XML 的多功能性

XML 贯穿于现代电子出版系统的整个流程,利用本项目的 XML,您不仅仅能够将数据转换成 HTML,还可以做大量其他事情。您可以编写 XSLT 电子表格来使用 W3C XSL-FO 标准创建 PDF 版本;可以创建适合于在 Sony 电子书阅读器、iPhones 和 iPads上阅读的 epub 电子书籍;也可以将 XML 存储在基于 XML 的数据库中,便于以后用 XQuery 查询。

项目最困难的部分 — 从三个源抽取数据并组合成典型工具可以使用的格式 — 现在已经完成,其实并不是很难。所有剩下的工作就是将最后一步产生的 XML 转换成 HTML,这是由批文件利用 XSLT 电子表格 SPARQLXML2HTML.xsl 完成的。查询引擎返回的 XML 具有一种常规的表状结构,这使得电子表格在创建 analystReport.html 报表时很容易找到它需要的数据。(我使用了开源 libxslt C 库附带的 xsltproc XSLT 处理程序来应用电子表格。若要改为使用 Xalan 或 Saxon,只需要更改命令行中参数的顺序即可。)

符合 SPARQL Query Results XML Format 规范的查询结果是一个大的 sparql 元素,头部信息在 head 元素中,实际的结果在 results 元素中。results 元素为结果中的每一行保留一个 result 元素,而每个 result 元素为这一行中的每个值都具有一个 binding 元素。

清单 3 展示了来自 SPARQLXML2HTML.xsl 的 XSLT 电子表格模板,用于处理 result 元素:

清单 3. 用于处理 result 元素的 XSLT 电子表格模板
<xsl:template match="s:result">

  <tr><td colspan="3"><hr/></td></tr>

  <tr>
    <td><xsl:apply-templates select="s:binding[@name='coName']"/></td>
    <td colspan="3"><xsl:apply-templates select="s:binding[@name='tickerSymbol']"/>
    $<xsl:apply-templates select="s:binding[@name='lastPrice']"/>
    at <xsl:apply-templates select="s:binding[@name='quoteDateTime']"/>
  </td>    </tr>

  <tr>
    <td><b>2009 figures:</b></td>
    <td>
      <b>Revenue </b>
      <xsl:apply-templates select="s:binding[@name='revenue']"/>
    </td>
    <td>
      <b>Net Income </b>
      <xsl:apply-templates select="s:binding[@name='netIncome']"/>
    </td>
  </tr>

  <tr>
    <td colspan="3">
      <xsl:apply-templates select="s:binding[@name='abstract']"/>
    </td>
  </tr>


  <tr class="rec">
    <td>
      <b>Analyst </b>
      <xsl:apply-templates select="s:binding[@name='analyst']"/>
    </td>
    <td>
      <b>Recommendation </b>
      <xsl:apply-templates select="s:binding[@name='recommendation']"/>
    </td>
    <td>
      <b>Date </b>
      <xsl:apply-templates select="s:binding[@name='recDateTime']"/>
    </td>
  </tr>

  <tr>
    <td colspan="3">
      <xsl:apply-templates select="s:binding[@name='description']"/>
    </td>
  </tr>

</xsl:template>

清单 3 中的模板创建单个 HTML 表行,行中的每个单元格保留返回的一段信息或者该信息的一个标签。


驱动程序批文件

build.bat 批文件在 10 步中完成以上所有操作:

  1. 设置 Java CLASSPATH 以包含 arq 工具。这一行假设 ARQROOT 环境变量已经设置为此工具的主目录。(参见 参考资料,阅读 关于 arq 的文档。)

  2. 使用 xls2rdf.py Python 脚本,从 analystRecs.xls 电子表格读取数据,并作为 RDF 保存在 analystRecs.rdf 文件中。

  3. 利用 arq 和存储在 augmentAnalystRecs.spq 文件中的 SPARQL 查询,从 analystRecs.rdf 读取公司名称并创建文件 coNamesWithLangTags.n3,该文件中每个公司名称都包含一个 en 语言标记。这使得交叉引用带有 DBpedia 数据的数据更为容易。

  4. 将 MakeGetTickerInfo.xsl XSLT 电子表格应用于 analystRecs.rdf,输出批文件 getTickerInfo.bat,它从 Yahoo! 服务检索股价数据。

  5. 运行 getTickerInfo.bat,它将 Yahoo! 数据检索为一个 CSV 文件,即 quoteData.csv。

  6. 运行 yahooCSV2RDF.pl Perl 脚本,将 quoteData.csv 转换成 quoteData.rdf RDF 文件。

  7. 将 MakeGetDbpediaData.xsl XSLT 电子表格应用于 analystRecs.rdf,以创建 getDbpediaData.bat 批文件,它从 DBpedia 检索公司数据。此批文件的每一行调用 cURL,给它传递一个 URI 参数,其中具有一个内嵌的 SPARQL 查询,负责检索一个公司的数据。

  8. 运行 getDbpediaData.bat 批文件,并将输出保存在 dbpedia.n3 文件中。

  9. 针对前面创建的四个数据文件(analystRecs.rdf、quoteData.rdf、coNamesWithLangTags.n3 和 dbpedia.n3),运行 PickDataForReport.spq 中的 SPARQL 查询,并将结果的 XML 版本保持在 reportData.xml 中。

  10. 将 SPARQLXML2HTML.xsl XSLT 电子表格应用于 reportData.xml 文件,以创建最终的报表文件 analystReport.html。

其他一些工具可能合并和自动化了一些步骤,实现与此相同的架构会更容易,但是要做的基本工作是相同的。


扩展应用程序

组合三个源的数据创建囊括 9 家公司的报表,对于使用我刚才介绍的技术来说是很小的规模。开源的 D2RQ 接口让您可以将关系数据当作一个三元组集合对待,因而该数据可以合并到这样的应用程序中。例如,假设一个这样的财务机构,它将有关其客户股票投资组合的数据存储在一个关系数据库系统中,比如 MySQL、DB2 或 Oracle。向本文描述的应用程序增加一点代码,就可以让它为每个客户产生类似于 analystReport.html 的定制报表,只列出此客户持有的股票,包括现值 — 通过将来自 Yahoo! 的股价乘以持有的股数计算得出。

整个应用程序不需要 RDF Schema 或 OWL 本体语言。但是这种模式元数据也存储为三元组,所以您若确实想要合并此类数据的话,它是又一类输入数据,可以增强您组合来创建报表的数据。使用这些模式标准存储规则(或者类似的东西)和其他关系元数据,而不是将它们存储在编译后的代码中,这增加了业务逻辑更易于维护和移植的优势。

日益增长的 Linked Data 源为您提供了越来越多的数据合并到应用程序,而语义 Web 标准为将此数据与其他数据源混合并匹配带来了新的灵活性。很多企业也发现,符合这些标准的工具对于在加入任何公共可用的数据之前在其企业内组合多个源的数据是很有价值的。有很多新工具可用于让所有这一切更为容易,但是正如您在这里看到的,一些熟悉的、受信任的老工具和技术在以有用的新方式合并数据方面也扮演了重要角色。


下载

描述名字大小
批文件、它调用的脚本,以及样例数据comboPubPrivData.zip86KB

参考资料

学习

获得产品和技术

讨论

条评论

developerWorks: 登录

标有星(*)号的字段是必填字段。


需要一个 IBM ID?
忘记 IBM ID?


忘记密码?
更改您的密码

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件

 


在您首次登录 developerWorks 时,会为您创建一份个人概要。您的个人概要中的信息(您的姓名、国家/地区,以及公司名称)是公开显示的,而且会随着您发布的任何内容一起显示,除非您选择隐藏您的公司名称。您可以随时更新您的 IBM 帐户。

所有提交的信息确保安全。

选择您的昵称



当您初次登录到 developerWorks 时,将会为您创建一份概要信息,您需要指定一个昵称。您的昵称将和您在 developerWorks 发布的内容显示在一起。

昵称长度在 3 至 31 个字符之间。 您的昵称在 developerWorks 社区中必须是唯一的,并且出于隐私保护的原因,不能是您的电子邮件地址。

标有星(*)号的字段是必填字段。

(昵称长度在 3 至 31 个字符之间)

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件.

 


所有提交的信息确保安全。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=XML
ArticleID=555986
ArticleTitle=利用语义 Web 技术集成异构数据
publish-date=10252010