Wikidata是一个大型结构化开源知识图,为维基百科等项目提供支持。我们可使用SPARQL(Wikidata官方Tutorial)对其进行查询。SPARQL是一种专为 RDF(Resource Description Framework)数据模型设计的查询语言。RDF通过三元组(主语subject,谓词predicate,宾语object)来组织数据。我们可在WDQS (WikiData Query Service)中使用SPARQL对Wikidata进行在线查询。
Wikidata介绍
实体和属性
Wikidata中最基本概念为实体(Entity)和属性(Property)。由于语义多样性,每个实体和属性都会以字母加数字的形式进行唯一化,实体以Q为前缀,属性以P为前缀,如Q148 (China),P31 (Instance of)。实体和属性分别构成了整个Wikidata知识图的节点和边。需注意的是,属性并不一定为知识图的一条边(连接两个实体)。这种情况十分常见,如P31 (Instance of) 用于表明实体所属的类别,将指向该实体对应的父类实体;而P1082 (Population) 用于表明实体(如某个国家)的人口数量,将直接对应一个数字。此外,属性不一定只对应一个值,由于人口会随时间不断变化,因此P1082 (Population) 通常会有多个对应不同时间戳的值。
数据结构
由于在线查询受制于网速,可在WikidataDumps下载Wikidata的数据备份。如下载entities/latest-all.json.bz2
,即可将整个Wikidata的知识图数据下载至一个json文件中(压缩文件约100GB,解压文件超过1TB)。json文件包含一个列表,列表中每个元素为一个字典,每个字典包含如下字段:
- type:类型,实体item或属性property。大部分是实体item,还有property。
- id:唯一标识符。
- labels:多语言标签,即名称。
- descriptions:多语言描述。
- aliases:多语言别名。
- claims:声明,包含属性及其对应的值。构建知识图最重要的字段。
- sitelinks:在其他维基项目中的链接,如中文wiki、法文wiki等。
- pageid:在维基百科等站点中的页面 ID。
- ns:所在的命名空间 (namespace)。条目通常在 0 命名空间,而用户页面在 2 命名空间。
- title:标题。
- lastrevid:最后一次修改的版本 ID。
- modified:最后修改时间。
其中,声明claims的字典结构较为复杂,以属性标识符P[...]
为键。每个键对应一个列表,存放相应的多条属性内容。属性内容字典结构如下:
- mainsnak:主体部分,包含属性和属性值
- snaktype:mainsnak 的类型。常见有:value表示有有效的属性值;novalue表示没有值;somevalue表示值未知或不确定。
- property:属性的ID(例如:P31)。
- datavalue:属性的值,可能是不同的数据类型,如实体、时间、量化数据等。
- value:具体的值(例如:Q5,表示人类)。
- type:值的类型,常见的类型有:
- wikibase-entityid:表示实体(Item 或 Property)类型。
- time:表示时间。
- quantity:表示量化数据。
- string:表示字符串(例如:文本类型的描述)。
- datatype:值的数据类型,通常是 wikibase-item(指向另一个实体)或 quantity(表示数量)。
- type:性质。可取值如:statement,最常见,表示这是一个有效的声明;mediainfo表示与媒体文件相关的信息;sitelinks涉及网站链接。
- qualifiers:限定条件,用来描述属性值的更多信息(通常是一个列表)。例如,某个属性值可能会有时间戳(时间限定)、地点限定等。
- property:限定条件的属性ID。
- datavalue:限定条件的值,通常是某个属性的具体内容。
- qualifiers-order:限定条件的字段顺序,帮助理解属性的附加信息。
- rank:声明的等级。常见的等级有:
- normal:普通等级。
- preferred:首选等级(如果存在多个声明)。
- deprecated:已弃用的声明。
- references:该声明的参考来源,通常是引用的文献或其他来源。
- snaks:引用的具体内容,类似于声明的 mainsnak,包括属性ID和对应的值。
- snaks-order:引用的属性的顺序。
- id:声明的唯一ID(用于区分不同的声明)。
SPARQL-Wikidata查询
以下通过简单例子来介绍如何使用SPARQL查询Wikidata知识图。语法类似SQL,利用SELECT
和WHERE
,其关键是使用主谓宾三元组来构成查询。
基本用法 — 主谓宾三元组
查询巴赫的所有孩子:
SELECT ?child
WHERE
{
# ?child father Bach
?child wdt:P22 wd:Q1339.
}
其中?child
为待查询变量,可随意命名;wd
表示WikiData的简写,用于引用实体;wdt
表示WikiData Truthy,用于引用实体属性的值。语句连起来即:有属性father (P22)
值为实体Bach (Q1339)
的实体。以上将查询到实体ID的列表。如果要在列表中加上标签列,可加上wikidata的魔术语句:
SELECT ?child ?childLabel
WHERE
{
# ?child father Bach
?child wdt:P22 wd:Q1339.
SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}
其中wikibase:label
为指定实体标签的固定字段。标签变量?childLabel
的命名是固定的:必须以为要查询的实体的变量为前缀,即?child
;并以首字母大写的待查询字段为后缀,即Label
。
巴赫和Maria Barbara Bach生的孩子中,既是作曲家又是钢琴家的孩子:
SELECT ?child
WHERE
{
?child wdt:P22 wd:Q1339;
wdt:P25 wd:Q57487; # P25: mother
wdt:P106 wd:Q36834, wd:Q486748. # P106: occupation
}
这里展示了分号;
逗号,
和句号.
的用法和区别。如分号可用于省略主语?child
,逗号可用于省略谓语wdt:P106
。
巴赫的(外)孙子/女:
SELECT ?grandChild
WHERE
{
wd:Q1339 wdt:P40 ?child. # P40: child
?child wdt:P40 ?grandChild.
}
这里展示了一个多跳查询,即通过?child
作为中间跳板,限定了?grandChild
与巴赫Q1339
的关系。可进一步简化为:
SELECT ?grandChild
WHERE
{
wd:Q1339 wdt:P40 [ wdt:P40 ?grandChild ].
}
以上使用方括号[]
来表达“有以?grandChild
为孩子的实体”,从而省略了前面的跳板变量?child
。可理解为一个使用定语从句的复合句:Bach has a child who has a child ?grandchild.
。
符号拓展/*+|
符号/
表示属性路径,用于连接多条属性,构成多跳查询;符号*+
类似正则表达式,*
表示匹配零个或多个属性,+
表示匹配一个或多个属性;符号|
表示“或”。以下展示代码实例。
所有艺术作品:
SELECT ?work ?workLabel
WHERE
{
?work wdt:P31/wdt:P279* wd:Q838948. # instance of any subclass of work of art
SERVICE wikibase:label { bd:serviceParam wikibase:language "[AUTO_LANGUAGE]". }
}
巴赫的所有后代:
SELECT ?descendant ?descendantLabel
WHERE
{
wd:Q1339 wdt:P40+ ?descendant.
SERVICE wikibase:label { bd:serviceParam wikibase:language "[AUTO_LANGUAGE]". }
}
巴赫的所有后代:
SELECT ?descendant ?descendantLabel
WHERE
{
?descendant (wdt:P22|wdt:P25)+ wd:Q1339.
SERVICE wikibase:label { bd:serviceParam wikibase:language "[AUTO_LANGUAGE]". }
}
此外,其中的问号?
也是有语义的,表示:匹配一个或零个元素。
声明限定 Qualifiers
用Qualifiers来对要查询的实体进行细粒度限定。
排序和数量限制
用ORDER BY
对查询结果进行排序,用LIMIT
限定返回结果的最大数量。
降序返回人口最大的前十个主权国家:
SELECT ?country ?countryLabel ?population
WHERE
{
?country wdt:P31/wdt:P279* wd:Q3624078; # P31: instance of; P279: subclass of; Q3624078: sovereign state
wdt:P1082 ?population. # P1082: population
SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}
ORDER BY DESC(?population)
LIMIT 10
DESC
表示降序,ASC
表示升序,默认升序。
可选条件
如果想返回部分字段,但不想让其影响检索条件,可使用OPTIONAL
。
所有Arthur Conan Doyle的书,并且检索的字段title等是可选的:
SELECT ?book ?title ?illustratorLabel ?publisherLabel ?published
WHERE
{
?book wdt:P50 wd:Q35610. # P50: auther; Q35610: Arthur Conan Doyle
OPTIONAL { ?book wdt:P1476 ?title. }
OPTIONAL { ?book wdt:P110 ?illustrator. }
OPTIONAL { ?book wdt:P123 ?publisher. }
OPTIONAL { ?book wdt:P577 ?published. }
SERVICE wikibase:label { bd:serviceParam wikibase:language "[AUTO_LANGUAGE]". }
}
其中title、illustrator等的匹配并不影响?book wdt:P50 wd:Q35610.
的结果,能匹配上就返回值,否则该值填空。注意和下面代码的区别:
SELECT ?book ?title ?illustratorLabel ?publisherLabel ?published
WHERE
{
?book wdt:P50 wd:Q35610.
OPTIONAL {
?book wdt:P1476 ?title;
wdt:P110 ?illustrator;
wdt:P123 ?publisher;
wdt:P577 ?published.
}
SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}
这个是OPTIONAL
中任意字段不匹配,全都填空。
表达式FILTER
和BIND
用表达式进行判断等操作。用到再记录。
组合GROUPING
把结果通过某个字段组合起来。用到再记录。