中文维基百科分类提取(jwpl)--构建知识图谱数据获取
首先感谢 :
1.https://blog.csdn.net/qq_39023569/article/details/88556301
2.https://www.cnblogs.com/CherishFX/p/5280259.html
3.https://www.cs.bgu.ac.il/~elhadad/nlp12/jwpl/wikification.html
4.https://blog.csdn.net/Icy233333/article/details/80383336
一。中文维基数据准备。
https://dumps.wikimedia.org/zhwiki/latest/
选择:
LANGCODE]wiki-[DATE]-pages-articles.xml.bz2
[LANGCODE]wiki-[DATE]-pagelinks.sql.gz
[LANGCODE]wiki-[DATE]-categorylinks.sql.gz
注:维基服务器限流,并且时不时会中断。可以直接使用linux 的 wget -c https://xxxxxxxxxxxxxxxxxxxx 方式实现可断点续接的下载。
下载完后放在一个文件夹下。 我放在 F:\zhwiki2019\~ 下。
二。下载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 文件下载。
下载后和数据放在同一目录下。
三。打开cmd,cd到zhwiki2019目录下,输入以下命令解析。
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文件的目录,比如: ~/En2019
我的命令:
java -Dfile.encoding=utf8 -cp de.tudarmstadt.ukp.wikipedia.datamachine-0.9.1-jar-with-dependencies.jar de.tudarmstadt.ukp.wikipedia.datamachine.domain.JWPLDataMachine chinese Contents Disambiguation_pages ~/zhwiki2019
如果你的系统默认编码不是utf-8(比如windows), 可能需要再加一个参数:-Dfile.encoding=utf8;
解析的时间看数据量的大小和你的cpu。之后会在output下生成11个txt.这11个txt就是之后要导入mysql的11个表。
这些文件的解释:
1 category --> 类别信息 2 pageId:类别ID,唯一 3 name:类别名 4 5 category_inlinks --> 指向类别的链接信息 6 id:类别ID,不唯一 7 inLinks:该类别父类ID,也就是指向该类别的类别ID 8 9 category_outlinks --> 类别指向的链接信息 10 id:类别ID,不唯一 11 outLinks:该类别子类ID,也就是该类别指向的那些类别的ID 12 13 category_pages --> 页面与类别的关系表 14 id:类别ID,不唯一 15 pages:属于该类别ID的页面ID 16 17 metadata --> 该wikipedia的一些元信息,只有一条记录 18 language:语言 19 disambiguationCategory:运行DataMachine填写的消歧类别 20 mainCategory:运行DataMachine填写的顶层类别 21 nrofPages:页面个数 22 nrofRedirects:重定向个数 23 nrofDisambiguationPages:消歧页面个数 24 nrofCategories:类别个数 25 version 26 27 page --> 页面信息 28 pageId:页面ID 29 name:名字 30 text:全文,包含wikimeida的标记信息 31 isDisambiguation:是否是消岐页面 32 33 page_categories --> 页面与类别的关系表与category_pages信息重复 34 35 page_inlinks --> 指向页面的页面信息 36 id:页面ID,不唯一 37 inLinks:指向该页面ID的页面ID 38 39 page_outlinks 40 id:页面ID,不唯一 41 outlinks:该页面ID指向的页面ID 42 43 page_redirects 44 id:页面ID,不唯一 45 redirects:重定向到该页面ID的所有页面ID 46 47 pagemapline --> 所有页面的title信息,处理重定向等有用处 48 id:该页面ID 49 name:页面title名字 50 pageID:页面ID,如果该页面是重定向页面,该pageID是其指向的那个包含信息的页面ID 51 stem:***暂无信息 52 lemma:***暂无信息
四。mysql 创建 库。(必须要mysql5.x版本。。我就是8.0.12失败找了原因重新下载了5.7.27版本的(错误:java.sql.SQLException: java.lang.ClassCastException: class java.math.BigInteger cannot be cast to ....)。jwpl通过C3P0来获得datasource.是获取datasource的阶段失败。)
1. 创建数据库命令(数据库名DB_NAME可以自行设定):注意要保证创建的数据库的编码是utf-8
CREATE DATABASE [DB_NAME] DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci;
我的DB_NAME是zhwiki.
2.创建所有的表,下载包含所有表结构的sql脚本:jwpl_tables.sql脚本,在mysql命令下执行改脚本:
mysql> use [DB_NAME]; mysql> source jwpl_tables.sql; #注意jwpl_tables.sql所在的路径(可以cd 到jwpl_tables.sql的目录下直接输入这个命令。)
3.因为我们的数据上传到数据库是存在mysql data目录下的,可以通过命令
mysql>show global variables like "%datadir%"
来查看你的数据库文件存放目录,我这里是在C盘,空间不够,所以需要修改data路径,将数据库data移到其他空间足够的盘,具体可以参考 https://blog.csdn.net/wangyan_z/article/details/81089211
,来修改你的data路径,这里不过多说明。
4,导入数据到mysql中
一个表一个表的导入,进入之前创建的用户的数据库
load data infile 'F:/zhwiki2019/output/Category.txt' into table category;
1 load data infile 'F:/zhwiki2019/output/Category.txt' into table category; 2 3 load data infile 'F:/zhwiki2019/output/category_inlinks.txt' into table category_inlinks; 4 5 load data infile 'F:/zhwiki2019/output/category_outlinks.txt' into table category_outlinks; 6 7 load data infile 'F:/zhwiki2019/output/category_pages.txt' into table category_pages; 8 9 load data infile 'F:/zhwiki2019/output/MetaData.txt' into table MetaData; 10 11 load data infile 'F:/zhwiki2019/output/Page.txt' into table Page; 12 13 load data infile 'F:/zhwiki2019/output/page_categories.txt' into table page_categories; 14 15 load data infile 'F:/zhwiki2019/output/page_inlinks.txt' into table page_inlinks; 16 17 load data infile 'F:/zhwiki2019/output/page_outlinks.txt' into table page_outlinks; 18 19 load data infile 'F:/zhwiki2019/output/page_redirects.txt' into table page_redirects; 20 21 load data infile 'F:/zhwiki2019/output/PageMapLine.txt' into table PageMapLine;
这里可能遇到mysql secure_file_priv问题。参考 https://blog.csdn.net/qq_35246620/article/details/78148505
解决完后,因为我处理的是中文维基的数据。mysql会报错utf8转义的问题。我查了我的系统编码和mysql的编码(参考https://bbs.csdn.net/topics/392478961),没有问题,只可能是数据的问题。打开后发现存在这样的数据: B\'z ,因为B‘z是一个组合。所以去掉 \ 就没问题了。自己可以写个小程序去掉。(或者去修改数据库的编码,通过navicat去编辑zhwiki的属性,然后选择utfmmd64)
五。使用JWPL jar包去访问维基百科数据
1.直接去maven库中下载整个jar-with-dependencies.jar。下载地址:http://search.maven.org/#search|ga|1|tudarmstadt.ukp
搜索de.tudarmstadt.ukp.wikipedia.api对应的 jar-with-dependencies.jar 文件,下载。
2.之后就是编码了。( jwpl论文:https://www.researchgate.net/publication/220745815_Extracting_Lexical_Semantic_Knowledge_from_Wikipedia_and_Wiktionary?ev=auth_pub)
论文中,说了工具主要以三个对象展开。直接给出代码。就可以看懂。
page对象:
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 }
运行的部分结果:
1 Queried string : Fruit 2 Title : Fruit 3 IsDisambiguationPage : false 4 redirect page query : false 5 # of ingoing links : 4454 6 # of outgoing links : 811 7 # of categories : 10
category对象:
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 }
1 Title : Towns in Germany 2 3 # super categories : 4 4 Towns by country 5 Commons category with local link same as on Wikidata 6 Populated places in Germany 7 Municipalities of Germany 8 9 # sub categories : 16 10 Towns in Rhineland-Palatinate 11 Towns in Lower Saxony 12 Towns in Saxony 13 Towns in Mecklenburg-Vorpommern 14 Towns in Saxony-Anhalt 15 University towns in Germany 16 Towns in Schleswig-Holstein 17 Seaside resorts in Germany 18 Towns in Baden-Württemberg 19 Towns in Thuringia 20 Towns in Hesse 21 Towns in Saarland 22 Towns in North Rhine-Westphalia 23 Towns in Brandenburg 24 Spa towns in Germany 25 Towns in Bavaria 26 27 # pages : 2 28 Oberreichenbach 29 Urfeld am Walchensee
其中,
Wikipedia 对象就是另一个主要的对象。page和categorty都要对这个对象进行访问,可以通过“单例模式”进行wikipedia的实例化。来节约资源,避免重复造轮子。
代码给出:
1 public class WikipediaUtil { 2 private static Wikipedia wiki = null; 3 4 public static Wikipedia getWikipedia() { 5 if (wiki == null) { 6 synchronized (wiki) { 7 if (wiki == null) { 8 try { 9 DatabaseConfiguration dbconfig = new DatabaseConfiguration(); 10 URL resource = WikipediaUtil.class.getClassLoader().getResource("zhwiki.properties"); 11 String file = resource.getFile(); 12 InputStream fileInputStream = new FileInputStream(file); 13 Properties properties = new Properties(); 14 properties.load(fileInputStream); 15 dbconfig.setHost(properties.getProperty("host")); 16 dbconfig.setDatabase(properties.getProperty("db")); 17 dbconfig.setUser(properties.getProperty("user")); 18 dbconfig.setPassword(properties.getProperty("password")); 19 dbconfig.setLanguage(WikiConstants.Language.chinese); 20 wiki = new Wikipedia(dbconfig); 21 } catch (Exception e) { 22 e.printStackTrace(); 23 } 24 } 25 } 26 } 27 return wiki; 28 } 29 }
剩下的探索吧...欢迎评论一起进步。