结构化数据到RDF由两种主要方式,一个是通过direct mapping,另一个通过R2RML语言这种,基于R2RML语言的方式更为灵活,定制性强。对于R2RML有一些好用的工具,此处我们使用d2rq工具,它基于R2RML-KIT。这里和前面电影的有些重复,但侧重点不同。
简介
Direct mapping 本质上是通过编写启发式规则将数据库中的表转换为RDF三元组, 但该方式灵活性不强。这里我们用 D2RQ 工具,它的主要功能是提供以虚拟的、只读的RDF图形式进入到关系型数据库中。也就是说比如你通过SPARQL端口查询,输入是SPARQL查询语言,D2RQ通过mapping文件将其转换为SQL语句在关系数据库上查询,因此实际上访问的是关系型数据库。同时你也可以使用它从数据库创建 RDF 格式的文件。
D2RQ 由自己的mapping语言,R2RML-kit。它和W3C推荐的R2RML类似。你可以通过D2RQ提供的工具来根据数据库自动生成mapping文件。你可以根据自己的需求去修改定制自己的mapping文件。
D2RQ 的框架如下图所示:
D2RQ 的安装
依赖:
- java1.5及以上的JDK
- 可用的数据库,Oracle, SQL Server, PostgreSQL, MySQL or HSQLDB,都可以。我们这里用 MYSQL.
- 可选)J2EE servlet容器,D2R即可以作为一个独立的Web服务器运行,也可以在其他现有的servlet容器内运行。
之后就是安装 D2RQ,首先下载D2RQ 安装包,放到合适的位置:
wget https://github.com/downloads/d2rq/d2rq/d2rq-0.8.1.tar.gz;
tar -xvzf d2rq-0.8.1.tar.gz;
接下来根据所使用的数据库安装相应的 JDBC 驱动。把JAR文件放在D2R Server的/lib目录下。Sun公司提供了一系列JDBC的下载,注意驱动的名字(e.g. org.postgresql.Driver for PostgreSQL or oracle.jdbc.driver.OracleDriver for Oracle),以及JDBC的URL(e.g. jdbc:mysql://servername/database for MySQL),这些在驱动的文件中可以找到。D2R Server中已经包括了MySQL和PostgreSQL。
D2RQ 的使用
生成 mapping 文件
使用 D2RQ 自带的 generate-mapping 工具, 根据数据库自动生成mapping文件。
./generate-mapping -u root -p nlp -o kg_demo_mapping_baidu_baike.ttl jdbc:mysql:///hudong_fenlei
其中 -u root 是数据库的用户名,-p nlp 是数据库的密码。 -o 指定生成 mapping 文件的名字。jdbc:mysql: /// 后面跟着的数据库的名字。
通过上述命令,我们将得到如下的 mapping 文件:
@prefix map: <#> .
@prefix db: <> .
@prefix vocab: <vocab/> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
@prefix d2rq: <http://www.wiwiss.fu-berlin.de/suhl/bizer/D2RQ/0.1#> .
@prefix jdbc: <http://d2rq.org/terms/jdbc/> .
map:database a d2rq:Database;
d2rq:jdbcDriver "com.mysql.jdbc.Driver";
d2rq:jdbcDSN "jdbc:mysql:///hudong_fenlei";
d2rq:username "root";
d2rq:password "nlp";
jdbc:autoReconnect "true";
jdbc:zeroDateTimeBehavior "convertToNull";
.
# Table lemmas
map:lemmas a d2rq:ClassMap;
d2rq:dataStorage map:database;
d2rq:uriPattern "lemmas/@@lemmas.title_id@@";
d2rq:class vocab:lemmas;
d2rq:classDefinitionLabel "lemmas";
.
map:lemmas__label a d2rq:PropertyBridge;
d2rq:belongsToClassMap map:lemmas;
d2rq:property rdfs:label;
d2rq:pattern "lemmas #@@lemmas.title_id@@";
.
map:lemmas_title a d2rq:PropertyBridge;
d2rq:belongsToClassMap map:lemmas;
d2rq:property vocab:lemmas_title;
d2rq:propertyDefinitionLabel "lemmas title";
d2rq:column "lemmas.title";
.
map:lemmas_title_id a d2rq:PropertyBridge;
d2rq:belongsToClassMap map:lemmas;
d2rq:property vocab:lemmas_title_id;
d2rq:propertyDefinitionLabel "lemmas title_id";
d2rq:column "lemmas.title_id";
d2rq:datatype xsd:integer;
.
map:lemmas_abstract a d2rq:PropertyBridge;
d2rq:belongsToClassMap map:lemmas;
d2rq:property vocab:lemmas_abstract;
d2rq:propertyDefinitionLabel "lemmas abstract";
d2rq:column "lemmas.abstract";
.
map:lemmas_infobox a d2rq:PropertyBridge;
d2rq:belongsToClassMap map:lemmas;
d2rq:property vocab:lemmas_infobox;
d2rq:propertyDefinitionLabel "lemmas infobox";
d2rq:column "lemmas.infobox";
.
map:lemmas_subject a d2rq:PropertyBridge;
d2rq:belongsToClassMap map:lemmas;
d2rq:property vocab:lemmas_subject;
d2rq:propertyDefinitionLabel "lemmas subject";
d2rq:column "lemmas.subject";
.
map:lemmas_disambi a d2rq:PropertyBridge;
d2rq:belongsToClassMap map:lemmas;
d2rq:property vocab:lemmas_disambi;
d2rq:propertyDefinitionLabel "lemmas disambi";
d2rq:column "lemmas.disambi";
.
map:lemmas_redirect a d2rq:PropertyBridge;
d2rq:belongsToClassMap map:lemmas;
d2rq:property vocab:lemmas_redirect;
d2rq:propertyDefinitionLabel "lemmas redirect";
d2rq:column "lemmas.redirect";
.
map:lemmas_curLink a d2rq:PropertyBridge;
d2rq:belongsToClassMap map:lemmas;
d2rq:property vocab:lemmas_curLink;
d2rq:propertyDefinitionLabel "lemmas curLink";
d2rq:column "lemmas.curLink";
.
map:lemmas_interPic a d2rq:PropertyBridge;
d2rq:belongsToClassMap map:lemmas;
d2rq:property vocab:lemmas_interPic;
d2rq:propertyDefinitionLabel "lemmas interPic";
d2rq:column "lemmas.interPic";
.
map:lemmas_interLink a d2rq:PropertyBridge;
d2rq:belongsToClassMap map:lemmas;
d2rq:property vocab:lemmas_interLink;
d2rq:propertyDefinitionLabel "lemmas interLink";
d2rq:column "lemmas.interLink";
.
map:lemmas_exterLink a d2rq:PropertyBridge;
d2rq:belongsToClassMap map:lemmas;
d2rq:property vocab:lemmas_exterLink;
d2rq:propertyDefinitionLabel "lemmas exterLink";
d2rq:column "lemmas.exterLink";
.
map:lemmas_relateLemma a d2rq:PropertyBridge;
d2rq:belongsToClassMap map:lemmas;
d2rq:property vocab:lemmas_relateLemma;
d2rq:propertyDefinitionLabel "lemmas relateLemma";
d2rq:column "lemmas.relateLemma";
.
map:lemmas_all_text a d2rq:PropertyBridge;
d2rq:belongsToClassMap map:lemmas;
d2rq:property vocab:lemmas_all_text;
d2rq:propertyDefinitionLabel "lemmas all_text";
d2rq:column "lemmas.all_text";
.
但是这个 mapping 文件我们还不能使用,需要做一些修改:
- vocab 这个我们不用,因此删除开头和正文中带有 vocab 的部分
- sed -i ‘/\@prefix vocab.* ./d’ kg_demo_mapping_hudong_fenlei.ttl
- sed -i ‘s/vocab/ /g’ kg_demo_mapping_hudong_fenlei.ttl
- 因为我们有互动和百度两个图谱,因此需要指定不同的前缀,对于互动百科
- sed -i ‘8a \@prefix : http://www.kghudong.com# .’ kg_demo_mapping_hudong_fenlei.ttl
- 因为是中文图谱,因此要指定文字编码:
- sed -i ‘s/d2rq:jdbcDSN “jdbc:mysql.*;/d2rq:jdbcDSN “jdbc:mysql:\/\/\/hudong_fenlei\?useUnicode=true\&characterEncoding=utf8”;/g’ kg_demo_mapping_hudong_fenlei.ttl
修改后,得到如下 mapping 文件:
@prefix map: <#> .
@prefix db: <> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
@prefix d2rq: <http://www.wiwiss.fu-berlin.de/suhl/bizer/D2RQ/0.1#> .
@prefix jdbc: <http://d2rq.org/terms/jdbc/> .
@prefix : <http://www.kghudong.com#> .
map:database a d2rq:Database;
d2rq:jdbcDriver "com.mysql.jdbc.Driver";
d2rq:jdbcDSN "jdbc:mysql:///hudong_fenlei?useUnicode=true&characterEncoding=utf8";
d2rq:username "root";
d2rq:password "nlp";
jdbc:autoReconnect "true";
jdbc:zeroDateTimeBehavior "convertToNull";
.
# Table lemmas
map:lemmas a d2rq:ClassMap;
d2rq:dataStorage map:database;
d2rq:uriPattern "lemmas/@@lemmas.title_id@@";
d2rq:class :lemmas;
d2rq:classDefinitionLabel "lemmas";
.
map:lemmas__label a d2rq:PropertyBridge;
d2rq:belongsToClassMap map:lemmas;
d2rq:property rdfs:label;
d2rq:pattern "lemmas #@@lemmas.title_id@@";
.
map:lemmas_title a d2rq:PropertyBridge;
d2rq:belongsToClassMap map:lemmas;
d2rq:property :lemmas_title;
d2rq:propertyDefinitionLabel "lemmas title";
d2rq:column "lemmas.title";
.
map:lemmas_title_id a d2rq:PropertyBridge;
d2rq:belongsToClassMap map:lemmas;
d2rq:property :lemmas_title_id;
d2rq:propertyDefinitionLabel "lemmas title_id";
d2rq:column "lemmas.title_id";
d2rq:datatype xsd:integer;
.
map:lemmas_abstract a d2rq:PropertyBridge;
d2rq:belongsToClassMap map:lemmas;
d2rq:property :lemmas_abstract;
d2rq:propertyDefinitionLabel "lemmas abstract";
d2rq:column "lemmas.abstract";
.
map:lemmas_infobox a d2rq:PropertyBridge;
d2rq:belongsToClassMap map:lemmas;
d2rq:property :lemmas_infobox;
d2rq:propertyDefinitionLabel "lemmas infobox";
d2rq:column "lemmas.infobox";
.
map:lemmas_subject a d2rq:PropertyBridge;
d2rq:belongsToClassMap map:lemmas;
d2rq:property :lemmas_subject;
d2rq:propertyDefinitionLabel "lemmas subject";
d2rq:column "lemmas.subject";
.
map:lemmas_disambi a d2rq:PropertyBridge;
d2rq:belongsToClassMap map:lemmas;
d2rq:property :lemmas_disambi;
d2rq:propertyDefinitionLabel "lemmas disambi";
d2rq:column "lemmas.disambi";
.
map:lemmas_redirect a d2rq:PropertyBridge;
d2rq:belongsToClassMap map:lemmas;
d2rq:property :lemmas_redirect;
d2rq:propertyDefinitionLabel "lemmas redirect";
d2rq:column "lemmas.redirect";
.
map:lemmas_curLink a d2rq:PropertyBridge;
d2rq:belongsToClassMap map:lemmas;
d2rq:property :lemmas_curLink;
d2rq:propertyDefinitionLabel "lemmas curLink";
d2rq:column "lemmas.curLink";
.
map:lemmas_interPic a d2rq:PropertyBridge;
d2rq:belongsToClassMap map:lemmas;
d2rq:property :lemmas_interPic;
d2rq:propertyDefinitionLabel "lemmas interPic";
d2rq:column "lemmas.interPic";
.
map:lemmas_interLink a d2rq:PropertyBridge;
d2rq:belongsToClassMap map:lemmas;
d2rq:property :lemmas_interLink;
d2rq:propertyDefinitionLabel "lemmas interLink";
d2rq:column "lemmas.interLink";
.
map:lemmas_exterLink a d2rq:PropertyBridge;
d2rq:belongsToClassMap map:lemmas;
d2rq:property :lemmas_exterLink;
d2rq:propertyDefinitionLabel "lemmas exterLink";
d2rq:column "lemmas.exterLink";
.
map:lemmas_relateLemma a d2rq:PropertyBridge;
d2rq:belongsToClassMap map:lemmas;
d2rq:property :lemmas_relateLemma;
d2rq:propertyDefinitionLabel "lemmas relateLemma";
d2rq:column "lemmas.relateLemma";
.
map:lemmas_all_text a d2rq:PropertyBridge;
d2rq:belongsToClassMap map:lemmas;
d2rq:property :lemmas_all_text;
d2rq:propertyDefinitionLabel "lemmas all_text";
d2rq:column "lemmas.all_text";
.
网页端访问
前面我们说 D2RQ提供虚拟的RDF访问么,现在我们来使用它。
首先进入到 d2rq文件夹内,运行
./d2r-server kg_demo_mapping_hudong_fenlei.ttl
命令开启服务器,然后通过网页端进行访问 http://localhost:2020/,顺利的话,你应该看到如下界面
点进 lemmas,随意打开一个,就可以看到该词条的信息:
三元组的生成
在生成 mapping 文件后,通过
./dump-rdf -o hudong_baike.nt kg_demo_mapping_hudong_fenlei.ttl
命令将数据转换为Ntriples。这一步比较慢,生成的文件也比较大,像互动百科有 430W 词条,得到的nt文件大概59个G,因此要做好预留空间。