使用JWPL (Java Wikipedia Library)操作维基百科数据

使用JWPL (Java Wikipedia Library)操作维基百科数据

1. JWPL介绍

  JWPL(Java Wikipedia Library)是一个开源的访问wikipeida数据的Java API包,提供了快速访问维基百科中包含的消息,如重定向、类别、文章和链接结构的结构性访问接口。它提供的DataMachine 工具类可快速解析wiki格式文件,生成mysql的数据txt文件,可通过mysqlimport 导入到本地数据库中。

  JWPL介绍官网:https://dkpro.github.io/dkpro-jwpl/

  JWPL的源码:https://github.com/dkpro/dkpro-jwpl

  JWPL的核心功能包括:1)快速有效地访问维基百科数据;2)分析处理Wiki格式数据;3)可以处理任何语言。

      除了以上列出的核心功能外,JWPL对存在编辑的历史数据的版本有再现的功能,这些版本再现工具有以下功能:1)重新生成某个历史时刻的维基百科数据(Time Machine);2)访问维基百科所有的版本信息(Revision Machine);3)专用的版本存储格式。

2. JWPL解析Wiki数据

  这里主要介绍如何搭建起使用JWPL那几个核心功能的平台,不包括后面利用版本数据的那几个工具。

  JWP核心API访问的数据都是存储在mysql数据库中的结构化的数据。所以,重点就是要怎么样把最原始的wikipeida dump数据转换成mysql数据库的记录格式,并导入mysql中,主要利用的就是JWPL提供的数据转换工具---DataMachine。

2.1下载维基百科历史数据

  从Wikipedia dump处下载需要的数据,选择语言[LANGCODE]和dump日期[DATE]: http://dumps.wikimedia.org/

  【注:Wikipedia数据也可直接到Wikipedia的ftp下载,省去找数据麻烦:ftp://wikipedia.c3sl.ufpr.br/wikipedia/,打开这地址后,选择你想要的版本(其中,enwiki表示英文版,zhwiki表示中文版),注意下载时,后面的名字要完全匹配,例如下pages-articles.xml.bz2时不要选择pages-articles-multistream.xml.bz2,因为按照本文方法不能解析multistream版本的

  最起码要下载下面三个文件:

 [LANGCODE]wiki-[DATE]-pages-articles.xml.bz2
 [LANGCODE]wiki-[DATE]-pagelinks.sql.gz
 [LANGCODE]wiki-[DATE]-categorylinks.sql.gz

   把该文件放入一个目录中,比如~/en2012

2.2下载JWPL DataMachine jar包

  直接去maven库中下载整个jar-with-dependencies.jar。下载地址:http://search.maven.org/#search|ga|1|tudarmstadt.ukp

  搜索de.tudarmstadt.ukp.wikipedia.datamachine对应的 jar-with-dependencies.jar 文件,下载。

2.3通过下载的DataMachine jar包 解析下载的历史数据

  命令:

java -cp jar-with-dependencies.jar de.tudarmstadt.ukp.wikipedia.datamachine.domain.JWPLDataMachine 
[LANGUAGE] [MAIN_CATEGORY_NAME] [DISAMBIGUATION_CATEGORY_NAME] [SOURCE_DIRECTORY]

  其中:

LANGUAGE: 指jwpl支持的语言,选择一个你下载的wikipedia语言,比如english, chinese
MAIN_CATEGORY_NAME: 填写一个Wikipedia类别层次上属于顶层的类别,比如:Contents
DISAMBIGUATION_CATEGORY_NAME: 填写一个有消歧类别的类别名,比如:Disambiguation_pages
SOURCE_DIRECTORY: 上面三个wikipedia文件的目录,比如: ~/en2012

  比如:

java -Xmx2g  -cp jar-with-dependencies.jar de.tudarmstadt.ukp.wikipedia.datamachine.domain.JWPLDataMachine 
english Contents Disambiguation_pages ~/en2012

  注:按照上述地址下载的DataMachine jar包名称会比给出的例子中的名称长,故需要把java命令行中的jar文件用完整的文件名表示即可,例如我下载的jar包文件名为:de.tudarmstadt.ukp.wikipedia.datamachine-0.9.2-jar-with-dependencies.jar,则相应的命令行应是:

java -Xmx2g  -cp de.tudarmstadt.ukp.wikipedia.datamachine-0.9.2-jar-with-dependencies.jar 
de.tudarmstadt.ukp.wikipedia.datamachine.domain.JWPLDataMachine english Contents Disambiguation_pages ~/en2012

  注意: 如果你的dump文件很大,发现上例中给JVM分别2G内存不够用,可能你就需要多分配写内存给JVM了,比如4G, "-Xmx4g"
  注意: 如果你的系统默认编码不是utf-8(比如windows), 可能需要再加一个参数:-Dfile.encoding=utf8 flag.

java  -Xmx4g -Dfile.encoding=utf8  -cp de.tudarmstadt.ukp.wikipedia.datamachine-0.9.2-jar-with-dependencies.jar
de.tudarmstadt.ukp.wikipedia.datamachine.domain.JWPLDataMachine english Contents Disambiguation_pages ~/en2012

  DataMachine jar解析维基百科数据会需要运行很长时间,大概一整天也有可能。运行完会在SOURCE_DIRECTORY目录下生成一个output目录,该目录里面有11个文件,这11个文件就是需要导入到mysql中的结构化数据了。

  注意:SOURCE_DIRECTORY 下还会产生一些.bin文件,这些都是临时文件,程序运行完就可以把他们删除了。

2.4创建相应的mysql数据库

  mysql版本:5.0+【由于数据量很大,所以最好选择磁盘空余空间100g+的磁盘安装mysql或者设置mysql data的存储空间】

  创建数据库命令(数据库名DB_NAME可以自行设定):注意要保证创建的数据库的编码是utf-8

CREATE DATABASE [DB_NAME] DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci;

  创建所有的表,下载包含所有表结构的sql脚本:jwpl_tables.sql脚本,在mysql命令下执行改脚本:

mysql> use [DB_NAME];
mysql> source jwpl_tables.sql;  #注意jwpl_tables.sql所在的路径

  

  导入output目录下的文件数据(.txt)到mysql数据库中:

mysqlimport -uUSER -p --local --default-character-set=utf8 [DB_NAME] ~/en2012/output/*.txt

  注意:如果导入出现问题,因为有些环境可能不支持通配符批量导入,那就可以在mysql命令行下利用load data infile一个表一个表导入,如:

mysql> load data infile 'E:/aawiki/output/Category.txt' into table category;

  将数据导入到对应的table中,所需要的时间也很长。

  各个表的结构:

 category --> 类别信息
     pageId:类别ID,唯一
     name:类别名

category_inlinks --> 指向类别的链接信息
     id:类别ID,不唯一
     inLinks:该类别父类ID,也就是指向该类别的类别ID

category_outlinks --> 类别指向的链接信息 
     id:类别ID,不唯一
     outLinks:该类别子类ID,也就是该类别指向的那些类别的ID

category_pages --> 页面与类别的关系表
     id:类别ID,不唯一
     pages:属于该类别ID的页面ID

metadata --> 该wikipedia的一些元信息,只有一条记录
     language:语言
     disambiguationCategory:运行DataMachine填写的消歧类别
     mainCategory:运行DataMachine填写的顶层类别
     nrofPages:页面个数
     nrofRedirects:重定向个数
     nrofDisambiguationPages:消歧页面个数
     nrofCategories:类别个数
     version

page --> 页面信息
     pageId:页面ID
     name:名字
     text:全文,包含wikimeida的标记信息
     isDisambiguation:是否是消岐页面

page_categories -->  页面与类别的关系表与category_pages信息重复

page_inlinks --> 指向页面的页面信息
     id:页面ID,不唯一
     inLinks:指向该页面ID的页面ID

page_outlinks
     id:页面ID,不唯一
     outlinks:该页面ID指向的页面ID

page_redirects
     id:页面ID,不唯一
     redirects:重定向到该页面ID的所有页面ID

pagemapline --> 所有页面的title信息,处理重定向等有用处
     id:该页面ID
     name:页面title名字
     pageID:页面ID,如果该页面是重定向页面,该pageID是其指向的那个包含信息的页面ID
     stem:***暂无信息
     lemma:***暂无信息

3. 在Eclipse中使用JWPL jar包去访问维基百科数据

(1)下载JWPL Wikipedia API

  直接去maven库中下载整个jar-with-dependencies.jar。下载地址:http://search.maven.org/#search|ga|1|tudarmstadt.ukp

  搜索de.tudarmstadt.ukp.wikipedia.api对应的 jar-with-dependencies.jar 文件,下载。

  【注意:这个de.tudarmstadt.ukp.wikipedia.api对应的jar包和2.2中的de.tudarmstadt.ukp.wikipedia.datamachine对应的jar包不一样,前者是在集成开发环境中操作wikipedia数据所需要用到的包,后者是将维基百科数据转换为mysql数据库中的数据所需要用到的包。

(2)下载JWPL的源码

  因为JWPL是一个开源的项目,所以可以下载其源码,然后导入Eclipse中后,可查看其源码。

  下载地址:https://github.com/dkpro/dkpro-jwpl

(3)在Eclipse中使用JWPL jar包

  在Eclipse中创建一个java project,然后导入(1)中下载的jar包(de.tudarmstadt.ukp.wikipedia.api-1.0.0-jar-with-dependencies.jar):

导入(2)中下载的JWPL源码(dkpro-jwpl-master.zip),导入后可以直接使用F3查看源码:

(4)在Eclipse中使用JWPL jar包去访问维基百科数据

示例代码1:显示页面信息

 1 import de.tudarmstadt.ukp.wikipedia.api.Category;
 2 import de.tudarmstadt.ukp.wikipedia.api.DatabaseConfiguration;
 3 import de.tudarmstadt.ukp.wikipedia.api.Page;
 4 import de.tudarmstadt.ukp.wikipedia.api.Title;
 5 import de.tudarmstadt.ukp.wikipedia.api.WikiConstants.Language;
 6 import de.tudarmstadt.ukp.wikipedia.api.Wikipedia;
 7 
 8 import static de.tudarmstadt.ukp.wikipedia.api.WikiConstants.LF;
 9 
10 public class ShowPageInfo {
11 
12     public static void main(String[] args) throws Exception {
13         // 数据库连接参数配置
14         DatabaseConfiguration dbConfig = new DatabaseConfiguration();
15         dbConfig.setHost("localhost");   //主机名
16         dbConfig.setDatabase("wikidb");  //数据库名
17         dbConfig.setUser("root");        //访问数据库的用户名
18         dbConfig.setPassword("root");    //访问数据库的密码
19         dbConfig.setLanguage(Language.english);
20         // 创建Wikipedia处理对象
21         Wikipedia wiki = new Wikipedia(dbConfig);
22         String title = "Fruit";
23         Page page = wiki.getPage(title);  
24         // wikipedia页面的title
25         System.out.println("Queried string       : " + title);
26         System.out.println("Title                : " + page.getTitle());
27         // 是否是消歧页面
28         System.out.println("IsDisambiguationPage : " + page.isDisambiguation());       
29         // 是否是重定向页面
30         System.out.println("redirect page query  : " + page.isRedirect());       
31         // 有多少个页面指向该页面
32         System.out.println("# of ingoing links   : " + page.getNumberOfInlinks());       
33         // 该页面指向了多少个页面
34         System.out.println("# of outgoing links  : " + page.getNumberOfOutlinks());
35         // 该页面属于多少个类别
36         System.out.println("# of categories      : " + page.getNumberOfCategories());
37         StringBuilder sb = new StringBuilder();
38         // 页面的所有重定向页面
39         sb.append("Redirects" + LF);
40         for (String redirect : page.getRedirects()) {
41             sb.append("  " + new Title(redirect).getPlainTitle() + LF);
42         }
43         sb.append(LF);       
44         // 页面的所述的所有类别
45         sb.append("Categories" + LF);
46         for (Category category : page.getCategories()) {
47             sb.append("  " + category.getTitle() + LF);
48         }
49         sb.append(LF);
50         // 指向该页面的所有页面
51         sb.append("In-Links" + LF);
52         for (Page inLinkPage : page.getInlinks()) {
53             sb.append("  " + inLinkPage.getTitle() + LF);
54         }
55         sb.append(LF);
56         // 该页面指向的所有页面
57         sb.append("Out-Links" + LF);
58         for (Page outLinkPage : page.getOutlinks()) {
59             sb.append("  " + outLinkPage.getTitle() + LF);
60         }       
61         System.out.println(sb);
62     }
63 }
View Code

运行的部分结果:

Queried string       : Fruit
Title                : Fruit
IsDisambiguationPage : false
redirect page query  : false
# of ingoing links   : 4454
# of outgoing links  : 811
# of categories      : 10
View Code

 

示例代码2:显示类别信息

 1 import de.tudarmstadt.ukp.wikipedia.api.Category;
 2 import de.tudarmstadt.ukp.wikipedia.api.DatabaseConfiguration;
 3 import de.tudarmstadt.ukp.wikipedia.api.Page;
 4 import de.tudarmstadt.ukp.wikipedia.api.WikiConstants.Language;
 5 import de.tudarmstadt.ukp.wikipedia.api.Wikipedia;
 6 import static de.tudarmstadt.ukp.wikipedia.api.WikiConstants.LF;
 7 
 8 public class ShowCategoryInfo {
 9     public static void main(String[] args) throws Exception {
10         //连接数据库的配置
11         DatabaseConfiguration dbConfig = new DatabaseConfiguration();
12         dbConfig.setHost("localhost");
13         dbConfig.setDatabase("wikidb");
14         dbConfig.setUser("root");
15         dbConfig.setPassword("root");
16         dbConfig.setLanguage(Language.english);
17         // 创建Wikipedia处理对象
18         Wikipedia wiki = new Wikipedia(dbConfig);
19         String title = "Towns in Germany";
20         // 创建类对象
21         Category cat = wiki.getCategory(title);
22         StringBuilder sb = new StringBuilder();
23         // 类别名
24         sb.append("Title : " + cat.getTitle() + LF);
25         sb.append(LF);
26         // 类别的父类信息
27         sb.append("# super categories : " + cat.getParents().size() + LF);
28         for (Category parent : cat.getParents()) {
29             sb.append("  " + parent.getTitle() + LF);
30         }
31         sb.append(LF);       
32         // 类别的子类信息
33         sb.append("# sub categories : " + cat.getChildren().size() + LF);
34         for (Category child : cat.getChildren()) {
35             sb.append("  " + child.getTitle() + LF);
36         }
37         sb.append(LF);
38         // 类别下的所有页面
39         sb.append("# pages : " + cat.getArticles().size() + LF);
40         for (Page page : cat.getArticles()) {
41             sb.append("  " + page.getTitle() + LF);
42         }       
43         System.out.println(sb); 
44     }
45 }
View Code

运行的结果:

Title : Towns in Germany

# super categories : 4
  Towns by country
  Commons category with local link same as on Wikidata
  Populated places in Germany
  Municipalities of Germany

# sub categories : 16
  Towns in Rhineland-Palatinate
  Towns in Lower Saxony
  Towns in Saxony
  Towns in Mecklenburg-Vorpommern
  Towns in Saxony-Anhalt
  University towns in Germany
  Towns in Schleswig-Holstein
  Seaside resorts in Germany
  Towns in Baden-Württemberg
  Towns in Thuringia
  Towns in Hesse
  Towns in Saarland
  Towns in North Rhine-Westphalia
  Towns in Brandenburg
  Spa towns in Germany
  Towns in Bavaria

# pages : 2
  Oberreichenbach
  Urfeld am Walchensee
View Code

 

【注】在最初程序运行的时候会报各种各样的debug错误提示,这是由于我们直接从下载的数据库脚本中恢复出的数据库中有各种信息的丢失,比如index,foreign key constraints等,此时,应按照提示的debug信息对相应的数据库表进行操作。比如我碰到的错误提示有:

DEBUG SchemaUpdate:226 - create index nameIndex on Page (name)

解决办法:直接按照提示在数据库中对表Page中的name列创建索引。

mysql> create index nameIndex on Page (name);

4. 资源

在此放上一些相关的资源,不包括维基百科历史数据,因为数据量太大了。

使用JWPL操作维基百科数据:https://yunpan.cn/cYvBsCxs79J8T  访问密码 749f

5. 感谢

Alex He使用JWPL工具操作wikipedia数据

zhong36060123的使用JWPL工具操作wikipedia数据

posted @ 2016-03-15 17:15  CherishFu  阅读(5367)  评论(2编辑  收藏  举报