📑 查看全课大纲(第 11 / 26 节)

面向半结构化数据的知识抽取

约 23 分钟

📺 正在播放小象官方高清录播(支持倍速与清晰度调节)

小象实战讲义 · 知识图谱

在构建知识图谱的过程中,除了从纯文本和结构化数据库中抽取知识,互联网上还存在着大量半结构化数据。这类数据介于结构化与非结构化之间,拥有一定的固定格式或模板,例如百科页面的信息框(infobox)、网页中的列表和表格。本节将系统讲解如何从半结构化数据中高效、准确地抽取知识,并形成标准化的 RDF 三元组,这是构建大规模开放域知识图谱(如 DBpedia)的关键技术。

💡 核心导读

  • 半结构化数据的定义与来源:理解什么是半结构化数据,其典型代表(如维基百科、商品列表页)及其在知识抽取中的优势。
  • 百科类知识抽取实践:深入剖析 DBpedia 和 Zhishi.me 的构建过程,学习如何从维基百科的页面结构(标题、摘要、信息框、分类、重定向等)中抽取并映射成 RDF 三元组。
  • 网页包装器技术:掌握从普通 HTML 网页中抽取结构化信息的三种方法:手工编写 XPath/CSS 选择器、基于标注的包装器归纳学习以及无监督的自动抽取。
  • Web Table 的实体链接:了解如何将网页表格中的单元格内容链接到知识库中的实体,解决表格数据缺乏上下文时的实体消歧问题。

半结构化数据概览

半结构化数据是指那些具有一定格式或结构,但结构不严格、不完全遵循固定模式的数据。与关系数据库的规整表格相比,它的结构更灵活;与纯文本相比,它又蕴含了可被机器识别的模式信息。

典型来源包括:

  1. 百科页面:如维基百科、百度百科。页面包含标题、摘要、信息框、分类标签、内部链接等结构化部分。
  2. 网页列表与详情页:如电商网站的商品列表、新闻网站的新闻摘要页。它们通常由后台模板生成,HTML 结构重复。
  3. 网页表格(Web Table):HTML 中的 <table> 标签内容,呈现行、列结构。

抽取优势:由于存在显式的结构标记(如 HTML 标签、维基语法),抽取规则相对明确,准确率和效率通常高于从纯文本中抽取。

百科类知识抽取:以 DBpedia 为例

DBpedia 是从维基百科中抽取结构化信息的经典项目,它形成了一个大规模、多语言的关联数据集(Linked Data)。其核心思想是将维基百科页面的各个组成部分,按照预设的规则,映射到 RDF 词汇和三元组上。DBpedia 覆盖 127 种语言、约 2800 万个实体,包含数亿条三元组。

抽取内容与映射规则

以下以一个虚构的维基百科页面“Tim Berners-Lee”(蒂姆·伯纳斯-李)为例,说明 DBpedia 的抽取过程:

  1. 页面标题 → 实体标签

    • 来源:页面标题 “Tim Berners-Lee”。
    • 映射:生成三元组,使用 rdfs:label 表示实体的可读标签。
    @prefix dbr: <http://dbpedia.org/resource/> .
    @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
    
    dbr:Tim_Berners-Lee rdfs:label "Tim Berners-Lee"@en .
  2. 摘要 → 实体描述

    • 来源:页面首段(Short Abstract)和全文摘要(Long Abstract)。
    • 映射:首段映射为 rdfs:comment,全文摘要映射为 dbo:abstract
    @prefix dbo: <http://dbpedia.org/ontology/> .
    @prefix dbr: <http://dbpedia.org/resource/> .
    @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
    
    dbr:Tim_Berners-Lee rdfs:comment "Sir Timothy John Berners-Lee, also known as TimBL, is an English engineer and computer scientist..."@en .
    dbr:Tim_Berners-Lee dbo:abstract "Sir Timothy John Berners-Lee (born 8 June 1955), also known as TimBL, is an English engineer and computer scientist, best known as the inventor of the World Wide Web."@en .
  3. 信息框(Infobox) → 实体类型与属性

    • 来源:页面右侧的“信息框”模板,如 {{Infobox person}}
    • 映射
      • 模板名:映射为实体的类型(rdf:type)。例如,Infobox person 映射为 dbo:Person
      • 属性-值对:信息框内的每一行(如 birth_date = {{Birth date and age|1955|6|8|df=y}})映射为一个属性三元组。属性名需要对齐到统一的 DBpedia 本体(dbo:)。
    @prefix dbr: <http://dbpedia.org/resource/> .
    @prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
    @prefix dbo: <http://dbpedia.org/ontology/> .
    @prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
    
    dbr:Tim_Berners-Lee rdf:type dbo:Person .
    dbr:Tim_Berners-Lee dbo:birthDate "1955-06-08"^^xsd:date .
    dbr:Tim_Berners-Lee dbo:birthPlace dbr:London .
    • 两级抽取策略:DBpedia 对 infobox 属性采用两层处理。第一层是 Generic Infobox Extraction(通用抽取,即 raw infobox properties)——直接保留 Wikipedia 中原有属性名(如 birthdatedateOfBirth 分别保留,不做映射),落在 dbp: 命名空间下,属性名会随维基模板漂移。第二层是 Mapping-based Infobox Extraction(基于映射的抽取)——在此基础上定义 DBpedia 本体(dbo:),通过人工规则将同义属性名对齐到统一本体属性(目前共有约 2795 个本体属性),这一二次对齐过程即本体对齐(Ontology Alignment)

    脚注:课件 P119 把这两层的名称标反了(将“保留原始属性名”标成 Mapping-based、将“定义 dbo: 本体做对齐”标成 Generic),此处按 DBpedia 官方口径更正。

  4. 图片与分类层级

    • 图片(Images):Wikipedia Commons 中的图片映射为 foaf:depiction
    • 分类层级:Wikipedia 分类系统中分类之间的父子关系映射为 skos:broader(上位)和 skos:narrower(下位)。
  5. 分类与链接 → 主题与关联

    • 分类(Categories):页面底部的分类标签(如 [[Category:Computer pioneers]])映射为实体的主题(dct:subject)。
    • 内部链接(Wikilinks):正文中的 [[World Wide Web]] 链接映射为 dbo:wikiPageWikiLink,表示页面间的关联。
    @prefix dct: <http://purl.org/dc/terms/> .
    @prefix dbr: <http://dbpedia.org/resource/> .
    @prefix dbo: <http://dbpedia.org/ontology/> .
    
    dbr:Tim_Berners-Lee dct:subject <http://dbpedia.org/resource/Category:Computer_pioneers> .
    dbr:Tim_Berners-Lee dbo:wikiPageWikiLink dbr:World_Wide_Web .
  6. 重定向与消歧 → 同义词与歧义处理

    • 重定向(Redirects):如 “TimBL” 页面重定向到 “Tim Berners-Lee”。这表示两个名称指向同一实体,使用 owl:sameAs 表示等价。
    • 消歧页(Disambiguation):如 “Apple” 可能指水果或公司。消歧页列出了多个可能实体,使用 dbo:wikiPageDisambiguates 关联。
    @prefix owl: <http://www.w3.org/2002/07/owl#> .
    @prefix dbr: <http://dbpedia.org/resource/> .
    @prefix dbo: <http://dbpedia.org/ontology/> .
    
    dbr:TimBL owl:sameAs dbr:Tim_Berners-Lee .
    <http://dbpedia.org/resource/Apple_(disambiguation)> dbo:wikiPageDisambiguates
        <http://dbpedia.org/resource/Apple_Inc.> ,
        <http://dbpedia.org/resource/Apple_(fruit)> .

从 DBpedia 到 Zhishi.me

Zhishi.me 是第一份中文大规模开放链接数据(Chinese Linking Open Data)项目,由东南大学研发。它采用了与 DBpedia 相似的思想,但数据源融合了中文维基百科、百度百科和互动百科,包含约 1000 万实体、2 亿三元组。

构建挑战与流程:

  1. 多源数据抽取:分别从三个百科站点抽取半结构化信息。
  2. 知识融合:这是核心难点,包括:
    • 实体融合(主语对齐):判断不同来源的“清华大学”页面是否指向同一实体。通常利用别名、关键属性(如地址、创办时间)进行冲突检测与合并。
    • 属性融合(谓语对齐):将“出生日期”、“生于”、“出生时间”等不同表述,对齐到统一的属性(如 dbo:birthDate)。
    • 值融合(宾语对齐):对于同一实体的同一属性,不同来源可能给出不同值。采用“精确性原则”(选最具体的日期)或“大多数原则”进行裁决。
  3. 服务发布:提供 Linked Data 访问、SPARQL 端点、API 和数据快照(Dump)等多种访问方式。

以下是一个简化的 Python 示例,模拟从一段类似百科摘要的文本中,使用正则表达式抽取特定属性(如“始建时间”):

import re

# 模拟一段百科摘要文本
abstract_text = "灵隐寺,又名云林寺,位于浙江省杭州市西湖区,始建于东晋咸和元年(326年)。"

# 定义抽取“始建时间”的正则模板
pattern_construction = r'始建于([^,。]+?)(?=|$)'
# 定义抽取“别名”的正则模板
pattern_alias = r'又名([^,。]+)'

match_con = re.search(pattern_construction, abstract_text)
match_alias = re.search(pattern_alias, abstract_text)

if match_con:
    print(f"始建时间: {match_con.group(1)}")  # 输出: 始建时间: 东晋咸和元年(326年)
if match_alias:
    print(f"别名: {match_alias.group(1)}")    # 输出: 别名: 云林寺

网页包装器生成技术

对于非百科类的半结构化网页(如商品列表、企业黄页),我们需要一种通用的方法来抽取信息,这种方法被称为包装器(Wrapper)。包装器是一个程序,它能够根据网页的结构化模式,定位并抽取目标数据。

方法一:手工编写包装器

原理:人工分析网页 HTML 结构,编写 XPath 或 CSS 选择器表达式来定位元素。

  • XPath:一种在 XML/HTML 文档中导航和选择节点的语言。
  • CSS 选择器:一种用于选择 HTML 元素的模式。

示例:假设要抽取某电商列表页中第一个商品的价格。

  • HTML 片段:
    <div id="J_goodsList">
      <ul>
        <li class="item">...<div class="p-price"><strong>3488</strong>元</div>...</li>
        <li class="item">...</li>
      </ul>
    </div>
  • 手工编写的 XPath: //*[@id="J_goodsList"]/ul/li[1]/div/div[@class='p-price']/strong
  • 手工编写的 CSS 选择器: #J_goodsList > ul > li:nth-child(1) > div > div.p-price > strong

优缺点:简单直接,适用于少量、稳定的页面。但维护成本高,页面结构一变就失效。

方法二:包装器归纳(有监督学习)

原理:通过标注少量训练样本(在网页上标记出要抽的数据),让算法自动学习出能够覆盖这些样本的、具有泛化能力的抽取规则(XPath)。

流程

  1. 网页清洗与标注:清理不规范的 HTML,并人工标注出需要抽取的数据项。
  2. 包装器空间生成:为每个标注项生成其精确的 XPath,然后通过泛化算法(如自底向上合并、编辑距离计算)生成一组候选的、更通用的 XPath。
  3. 包装器评估与选择:用准确率(Precision)和召回率(Recall)评估候选包装器,选择综合性能最好的。

示例:假设标注了表格中两个“姓名”单元格 n1 和 n2。

  • n1 的 XPath: /html/body/table/tbody/tr[2]/td[1]
  • n2 的 XPath: /html/body/table/tbody/tr[3]/td[1]
  • 泛化后的候选包装器 A: /html/body/table/tbody/*/td[1] (匹配所有行的第一列)
  • 泛化后的候选包装器 B: //td (匹配所有 td 单元格)
  • 评估:包装器 A 能精确抽取出所有“姓名”,准确率高;包装器 B 会抽出所有单元格,噪声大。因此选择 A。

方法三:自动抽取(无监督学习)

原理:不需要人工标注。基于观察:同一网站中结构相似的页面通常由同一个后台模板生成。通过聚类算法将结构相似的网页分组,然后通过比较组内网页的 HTML 树结构差异,自动推断出模板和数据的边界,从而生成包装器。

代表工具:RoadRunner。 核心算法:把两个相似页面解析成标签序列,通过标记序列对齐(tag sequence alignment)做差,归纳出无并集(union-free)正则文法,识别出共同的模板部分和可变的数据部分,用通配符(如 #PCDATA 代表文本,(..)+ 代表重复结构)生成包装器。

优缺点:无需标注,适合大规模站点。但可能抽取出无关信息,且对网页相似度要求高。

以下是一个使用 Python 标准库 xml.etree.ElementTree,通过 ElementPath 从一段 HTML 中抽取信息的示例:

import xml.etree.ElementTree as ET

html_content = """<html><body>
<div id="J_goodsList">
  <ul>
    <li class="item"><div class="p-name">华为P10</div><div class="p-price"><strong>3488</strong>元</div></li>
    <li class="item"><div class="p-name">iPhone 12</div><div class="p-price"><strong>5999</strong>元</div></li>
  </ul>
</div>
</body></html>"""

root = ET.fromstring(html_content)
# 使用 ElementPath 定位商品名称和价格(等价于简化版 XPath)
names = [div.text for div in root.findall('.//div[@class="p-name"]')]
prices = [strong.text for strong in root.findall('.//div[@class="p-price"]/strong')]

for name, price in zip(names, prices):
    print(f"商品: {name}, 价格: {price}元")
# 输出:
# 商品: 华为P10, 价格: 3488元
# 商品: iPhone 12, 价格: 5999元

从 Infobox 属性字典到 RDF 三元组

前面介绍了 DBpedia 如何将 infobox 的每个属性-值对映射为 RDF 三元组。下面用 rdflib 演示这一过程:先将 Wikipedia infobox 解析为 Python 字典,再按映射规则转换为 RDF 三元组。

from rdflib import Graph, Namespace, Literal, RDF, RDFS, XSD

# 模拟从 Wikipedia infobox 模板解析出的属性字典
infobox = {
    "name": "Tim Berners-Lee",
    "birth_date": "1955-06-08",
    "birth_place": "London",
}

# 定义 DBpedia 命名空间
DBR = Namespace("http://dbpedia.org/resource/")
DBO = Namespace("http://dbpedia.org/ontology/")

g = Graph()
person = DBR["Tim_Berners-Lee"]

# infobox 模板名 -> rdf:type
g.add((person, RDF.type, DBO.Person))
# 页面标题 -> rdfs:label
g.add((person, RDFS.label, Literal(infobox["name"], lang="en")))
# infobox 属性值 -> dbo: 属性三元组
g.add((person, DBO.birthDate, Literal(infobox["birth_date"], datatype=XSD.date)))
g.add((person, DBO.birthPlace, DBR[infobox["birth_place"]]))

# 验证:遍历图中的三元组
for s, p, o in g:
    print(f"({s}) -> ({p}) -> ({o})")
print(f"共 {len(g)} 条三元组")

Web Table 的实体链接

网页中的表格(Web Table)是一种特殊的半结构化数据。要理解其语义,需要将单元格中的文本链接(Link)到知识库中的特定实体,即实体链接(Entity Linking)。

挑战:表格缺乏丰富的上下文文本,但拥有行、列的结构化语境

流程

  1. 候选实体生成:对于单元格字符串“夏洛特”,通过字符串匹配在知识库中找到候选实体:夏洛特市(北卡罗来纳)、夏洛特市(伊利诺伊)、夏洛特黄蜂队等。
  2. 实体消歧:利用表格的行列上下文进行联合消歧。
    • 同行数据:同一行的“夏洛特”和“迈克尔·乔丹”可能相关。“迈克尔·乔丹”作为篮球运动员,更可能链接到“夏洛特黄蜂队”(他曾是老板)。
    • 同列数据:同一列的“洛杉矶”、“达拉斯”、“芝加哥”都是城市名,这提示该列可能为“城市”属性,从而帮助“夏洛特”消歧到城市实体。
  3. 构建与求解消歧图:将表格中所有单元格及其候选实体构建成一个图,节点包括字符串节点和实体节点,边表示它们之间的关联(如共现、语义相似度)。使用图算法(如 PageRank 的变种)进行全局推理,为每个单元格选择最合适的实体。

生成三元组:完成实体链接后,可以推导出表格隐含的关系。例如,一个“球员-国籍-俱乐部”表格,在链接实体后,可以生成 (里奥·梅西, 国籍, 阿根廷)(卡卡, 效力于, AC米兰) 等三元组。

📝 动手练一练

  1. 概念辨析:面向半结构化数据的知识抽取,与面向纯文本的知识抽取(如关系抽取)相比,主要优势和挑战分别是什么?
  2. 动手构造:观察以下简化的维基百科信息框文本,请尝试设计规则,将其转换为 RDF 三元组(使用 dbo: 前缀)。假设 dbr:Python_(programming_language) 是主体。
    {{Infobox programming language
    | name = Python
    | paradigm = Multi-paradigm: functional, object-oriented
    | designer = Guido van Rossum
    | first_release = 1991
    }}
    提示:paradigm可映射为dbo:programmingParadigmdesigner可映射为dbo:designerfirst_release可映射为dbo:releaseDate
👉 点击查看参考答案
  1. 优势:半结构化数据具有显式的结构标记(HTML标签、维基语法),抽取规则更明确,准确率和效率通常更高,可大规模自动化处理。 挑战:需要处理不同网站或页面间结构差异(包装器维护),需要对抽取出的异构属性进行对齐与融合(本体匹配),且页面结构可能动态变化导致包装器失效。
  2. 三元组构造示例
    @prefix dbr: <http://dbpedia.org/resource/> .
    @prefix dbo: <http://dbpedia.org/ontology/> .
    @prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
    
    <http://dbpedia.org/resource/Python_(programming_language)> dbo:programmingParadigm "Multi-paradigm: functional, object-oriented"@en ;
                                    dbo:designer dbr:Guido_van_Rossum ;
                                    dbo:releaseDate "1991"^^xsd:gYear .

本章小结

本节深入探讨了从半结构化数据中抽取知识的核心方法。我们学习了如何将维基百科丰富的页面结构转化为标准的 RDF 知识,理解了 DBpedia 和 Zhishi.me 的构建精髓。同时,掌握了针对通用网页的包装器技术,从手工编写到自动学习,以及如何处理网页表格中的实体链接问题。这些技术是构建和扩展大规模知识图谱数据源的关键。

📋 行动清单

  • 访问 DBpedia:打开 DBpedia 页面,搜索一个你熟悉的人物或概念,查看其被抽取出的 RDF 数据,直观感受从半结构化到结构化知识的转换。
  • 练习 XPath:使用浏览器的开发者工具(F12),打开一个新闻或商品列表页,尝试在 Console 中使用 $x('你的XPath') 来定位页面中的特定元素。
  • 思考融合问题:如果想从豆瓣电影和 IMDb 两个网站抽取电影信息构建图谱,你会面临哪些“知识融合”方面的挑战?尝试列出 2-3 点。

—— 小象教研组

配套学习资源与课件
  • 第3章课件:知识抽取与挖掘 I
    下载
  • 第3章练习(Assignment:Java + .ttl 数据)
    下载
  • 知识图谱课程思维导图(KG_Centralized.xmind 全课程结构图)
    下载
🎁 免费学习资源

领取《小象 11GB VIP 课件资料包与大厂真题手册》

包含全套实战 Jupyter 源码、清洗后数据集、大厂高频面试真题与专属学员答疑交流群。

  • 完整 Python / 数据分析 Jupyter 实战源码
  • 大厂真实业务数据集与练习题
  • 微信扫码添加顾问免费领取;想学什么,直接告诉顾问
微信二维码:扫码添加课程顾问微信扫码添加顾问