首先要从http://wordnet.princeton.edu/上下载WordNet,支持Windows系统的最新版本是WordNet2.1,是可执行文件,下载之后双击安装就可以了,记住安装目录,以后会用到。我的安装目录是C:/Program Files/WordNet/2.1。
然后下载MIT Java WordNet Interface,下载地址如下http://www.mit.edu/~markaf/prj/jwi/,我下载的版本是2.1.4,下载之后解压,会发现有一个 edu.mit.jwi_2.1.4_jdk的jar包。
现在准备工作已经做完了,除非你的机器还没有安装JDK或Eclipse,因为这两者是需要的,至少JDK是需要的。接下来打开Eclipse,创建一个新的Java Project,然后右键点击你的Project,在Build Path-->Configue Build Path...-->Java Build Path-->Libraries-->Add External Jars...选择刚才的edu.mit.jwi_2.1.4_jdk,这样你的Project里就包含了这个MIT的Library了。然后回到桌面右键点击“我的电脑”-->“属性”-->“高级”-->"环境变量",在系统变量中添加一个叫做WNHOME的变量,值就是你刚才安装WordNet的安装目录,我这里的值就是C:/Program Files/WordNet/2.1。这样做的目的一会儿就会明白。
重新启动Eclipse,在你的Project里建立一个新的包,在包里新建一个Java文件,内容如下:
package wordnettest;
import java.io.*;
import java.net.*;
import edu.mit.jwi.Dictionary;
import edu.mit.jwi.IDictionary;
import edu.mit.jwi.item.*;
public class hiwordnet {
public static void main(String[] args) throws IOException {
//建立指向WordNet词典目录的URL。
String wnhome = System.getenv("WNHOME");
String path = wnhome + File.separator + "dict";
URL url=null;
try{
url = new URL("file", null, path);
}
catch(MalformedURLException e){
e.printStackTrace();
}
if(url == null)
return;
//建立词典对象并打开它。
IDictionary dict = new Dictionary(url);
dict.open();
//查询dog这个词的第一种意思。
IIndexWord idxWord = dict.getIndexWord("enough", POS.ADVERB);
IWordID wordID = (IWordID)idxWord.getWordIDs().get(0);
IWord word = dict.getWord(wordID);
System.out.println("Id = " + wordID);
System.out.println("Lemma 词元 = " + word.getLemma());
System.out.println("Gloss注解 = " + word.getSynset().getGloss());
}
}
看过以上的代码就应该知道刚才添加WNHOME这个系统变量的意图了,就是为了在程序中使用WordNet的字典。现在运行这个Java程序,可得结果下:
Id = WID-00146900-R-??-enough
Lemma = enough
Gloss = as much as necessary; "Have I eaten enough?"; (`plenty' is nonstandard) "I've had plenty, thanks"
二、JWI装载WordNet到内存的遍历性能优化:
JWI2.2.x系列一个新的特点是可以将WordNet装载到内存中,这一举措大大的改善了遍历WordNet的性能。其中实现该功能的是,JWI的edu.mit.jwi.RAMDictionary类,该类可以设定是否将WordNet装入内存。
写一个遍历WordNet的函数trek(),对使用RAMDictionary来打开WordNet,对不装载入内存和装载入内存进行比较;
package wordnettest;
//JWI的edu.mit.jwi.RAMDictionary类,该类可以设定是否将WordNet装入内存。
//写一个遍历WordNet的函数trek(),对使用RAMDictionary来打开WordNet,对不装载入内存和装载入内存进行比较;
import java.io.File;
import java.io.IOException;
import java.util.Iterator;
import edu.mit.jwi.IDictionary;
import edu.mit.jwi.IRAMDictionary;
import edu.mit.jwi.RAMDictionary;
import edu.mit.jwi.data.ILoadPolicy;
import edu.mit.jwi.item.IIndexWord;
import edu.mit.jwi.item.IWordID;
import edu.mit.jwi.item.POS;
public class classramdictionaryTest {
public static void main(String[] args ) throws IOException, Exception{
String wnhome = System.getenv("WNHOME"); //获取环境变量WNHOM
String path = wnhome + File.separator+ "dict";
File wnDir=new File(path);
testRAMDictionary(wnDir);
}
public static void testRAMDictionary(File wnDir) throws IOException, InterruptedException{
IRAMDictionary dict=new RAMDictionary(wnDir, ILoadPolicy.NO_LOAD);
dict.open();
//周游WordNet
System.out.print("没装载前:\n");
trek(dict);
//now load into memor
System.out.print("\nLoading Wordnet into memory...");
long t=System.currentTimeMillis();
dict.load(true);
System.out.printf("装载时间:done(%1d msec)\n", System.currentTimeMillis()-t);
//装载后在周游
System.out.print("\n装载后:\n");
trek(dict);
}
/*
* this method is Achieved to trek around the WordNet
*/
public static void trek(IDictionary dict){
int tickNext=0;
int tickSize=20000;
int seen=0;
System.out.print("Treking across Wordnet");
long t=System.currentTimeMillis();
for(POS pos:POS.values()){ //遍历所有词性
for(Iterator
//遍历某一个词性的所有索引
for(IWordID wid:i.next().getWordIDs()){
//遍历每一个词的所有义项
seen+=dict.getWord(wid).getSynset().getWords().size();//获取某一个synsets所具有的词
if(seen>tickNext){
System.out.print(".");
tickNext=seen + tickSize;
}
}
}
}
System.out.printf("done (%1d msec)\n",System.currentTimeMillis()-t);
System.out.println("In my trek I saw "+ seen + " words");
}
}
执行的效果为:
没装载前
Treking across Wordnet...........................done (3765 msec)
In my trek I saw 523260 words
Loading Wordnet into memory...装载时间:done(10625 msec)
装载后:
Treking across Wordnet...........................done (328 msec)
In my trek I saw 523260 words
由结果可见,不装如内存的周游WordNet的时间为3765 ms,而装入内存后的周游时间为328 ms,结果中的10625ms把装入内存所消耗的时间。就周游的时间而言转入内存后的时间更快速。
三、JWI获取同义词以及抛出NullPointerException原因解析
获取一个词的Synset内的同义词,一下是一个示例:获取“go”的同义词。
import java.io.File;
import java.io.IOException;
import java.net.URL;
import edu.mit.jwi.Dictionary;
import edu.mit.jwi.IDictionary;
import edu.mit.jwi.item.IIndexWord;
import edu.mit.jwi.item.ISynset;
import edu.mit.jwi.item.IWord;
import edu.mit.jwi.item.IWordID;
import edu.mit.jwi.item.POS;
public class GetWordSynsetsTest {
public static void main(String[] args) throws IOException{
String wnhome = System.getenv("WNHOME"); //获取WordNet根目录环境变量WNHOME
String path = wnhome + File.separator+ "dict";
File wnDir=new File(path);
URL url=new URL("file", null, path);
IDictionary dict=new Dictionary(url);
dict.open();//打开词典
getSynonyms(dict); //testing
}
public static void getSynonyms(IDictionary dict){
// look up first sense of the word "go"
IIndexWord idxWord =dict.getIndexWord("go", POS.VERB);
IWordID wordID = idxWord.getWordIDs().get(0) ; // 1st meaning
IWord word = dict.getWord(wordID);
ISynset synset = word.getSynset (); //ISynset是一个词的同义词集的接口
// iterate over words associated with the synset
for(IWord w : synset.getWords())
System.out.println(w.getLemma());//打印同义词集中的每个同义词
}
}
执行的结果为:
travel
go
move
locomote
在获取一个IndexWord时,很容易抛出一个运行异常,即NullPointerException。这是因为在WordNet里找不着你想要的词。但是这个词在实际英语环境中是存在的。可能的原因如下:
1.所输入的词形式不对,比如:go写成了gone,或者dog写成dogs等非源词形式了。
2.可能是你在构造词时,在如getIndexWord("go", POS.VERB)函数中词性参数输入错误,比如上例中输入的词性是POS.ADVERB。由于go没有副词,所以汇报NullPointerException异常。
3.一些新的单词根本还没录入WordNet。
四、JWI寻找父类词
上义词Hypernyms,即俗称的父类,再次称为父类词。查找一个词的父类词,则使用JWI提供的ISynset对象的getRelatedSynsets(IPointerType)方法来寻找,其中IPointerType为Synsets之间的关系指针,通过设置其为Pointer.HYPERNYM则可以实现寻找该词的父类。
实例:
import java.io.File;
import java.io.IOException;
import java.util.Iterator;
import java.util.List;
import edu.mit.jwi.Dictionary;
import edu.mit.jwi.IDictionary;
import edu.mit.jwi.item.IIndexWord;
import edu.mit.jwi.item.ISynset;
import edu.mit.jwi.item.ISynsetID;
import edu.mit.jwi.item.IWord;
import edu.mit.jwi.item.IWordID;
import edu.mit.jwi.item.POS;
import edu.mit.jwi.item.Pointer;
public class GetHypernymsTest {
public static void main(String[] args) throws IOException{
String wnhome = System.getenv("WNHOME"); //获取WordNet根目录环境变量WNHOME
String path = wnhome + File.separator+ "dict";
File wnDir=new File(path);
IDictionary dict=new Dictionary(wnDir);
dict.open();//打开词典
getHypernyms(dict);//testing
}
public static void getHypernyms(IDictionary dict){
//获取指定的synset
IIndexWord idxWord = dict.getIndexWord("article", POS.NOUN);//获取dog的IndexWord
IWordID wordID = idxWord.getWordIDs().get(0); //取出第一个词义的词的ID号
IWord word = dict.getWord(wordID); //获取词
ISynset synset = word.getSynset(); //获取该词所在的Synset
// 获取hypernyms
List
// print out each hypernyms id and synonyms
List
for( ISynsetID sid : hypernyms ){
words = dict.getSynset(sid).getWords(); //从synset中获取一个Word的list
System.out.print(sid + "{");
for( Iterator
System.out.print(i.next().getLemma ());
if(i. hasNext ()){
System.out.print(", ");
}
}
System .out . println ("}");
}
}
}
执行结果为:
SID-06282025-N{nonfiction, nonfictional_prose}
SID-06186871-N{piece}
从结果看出article有两个父类,第一个为文学、小说、文章等,第二个指片段、一张、片等。