ICTCLAS2010的JNI调用实现过程
JNI是Java Native Interface的缩写,中文为JAVA本地调用,详细信息可以看百度百科关于JNI的介绍:
http://baike.baidu.com/view/1272329.htm?fr=ala0_1_1
如果觉的这里JNI调用没有讲清楚的话,(因为我主要通过一个完整的案例来讲的,所以过于JNI的详细的教程没有!)可以看这个网址的教程,我开始学的时候看到的,还可以了,入门还行:
http://developer.51cto.com/art/200509/2815.htm
JNI调用一般步骤:
以本讲解程序为例:
1)首先这样一句话:
static {
System.loadLibrary("ICTCLAS2010");
}
引入dll文件(就是要背Java调用的文件,在Windows操作系统是dll文件,所以不需要些后缀名)
2)然后根据接口文档(这个需要接口文档,如果是自己写的就应该知道),引入该dll中的需要的方法,并且都是native方法,只引入,不实现。
格式如下:
public native boolean ICTCLAS_Init(byte[] sPath);
把这些写入一个类中。
然后就可以在其他的类中调用这个类中的本地方法(native)了。
准备工作当然要把dll文件放在项目文件夹下边。
(其他的需要的配置文件,和一些文件也学要准备好!)
现在开始实现ICTCLAS2010的调用:
使用工具:Eclipse
下载ICTCLAS2010-packet-release,这里提供一个新浪共享资料的下载地址:
http://ishare.iask.sina.com.cn/f/7446738.html?from=dl
将下载好的文件解压,里边有许多文件,待会儿要用。
新建一个项目:
将解压文件夹中的Data文件夹,ICTCLAS2010.dll文件(就是我们需要调用的C++写的分词器了),ICTCLAS30.log文件(可以自己创建的,初始的时候是空的,是一个日志文件),Configure.xml配置文件(可以自己写,不过这里有现成的就直接拷过去了,然后根据自己的需要改改就好了),userdic.txt(用户词典文件,可以自己创建,然后再写代码的时候使用接口函数调用就可以了),还有一些其他的文件在这个程序里没有用到,所以不再说了!
编写第一个类是JNI调用的类ICTCLAS2010.java:
package ICTCLAS.kevin.zhang;
public class ICTCLAS2010 {
static {
System.loadLibrary("ICTCLAS2010");
}
//初始化
public native boolean ICTCLAS_Init(byte[] sPath);
//退出
public native boolean ICTCLAS_Exit();
//导入用户词典
public native int ICTCLAS_ImportUserDict(byte[] sPath);
//获取uni概率
public native float ICTCLAS_GetUniProb(byte[] sWord);
//判断词典中有没有这个词
public native boolean ICTCLAS_IsWord(byte[] sWord);
//一段文字的分词
public native byte[] ICTCLAS_ParagraphProcess(byte[] sSrc, int bPOSTagged);
//一个文本文件的分词
public native boolean ICTCLAS_FileProcess(byte[] sSrcFilename,
byte[] sDestFilename, int bPOSTagged);
public native byte[] nativeProcAPara(byte[] src);
public native int ICTCLAS_AddUserWord(byte[] sWord);
public native int ICTCLAS_SaveTheUsrDic();
public native int ICTCLAS_DelUsrWord(byte[] sWord);
public native int ICTCLAS_KeyWord(byte[] resultKey, int nCountKey);
public native long ICTCLAS_FingerPrint();
public native int ICTCLAS_SetPOSmap(int nPOSmap);
public native int ICTCLAS_GetElemLength(int nIndex);
}
上边调用的这些本地(native)方法,在接口文档(刚才下载的文件夹下的“文档“文件夹下边有个ICTCLAS2010接口文档.doc文件)中都是有详细介绍的,我的博文中也做了一些介绍,主要做翻译工作和整理工作
(http://blog.sina.com.cn/s/blog_5dc8d9a50100kwuy.html)。
然后第二个类Splitter.java是分词的主类:
package ICTCLAS.kevin.zhang;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
public class Splitter {
private ICTCLAS2010 ictclas = null;//创建上边第一个类的对象
private boolean available ;
public Splitter() throws IOException {
this.ictclas = new ICTCLAS2010();
this.available = init();
}
//初始化
private boolean init() throws IOException {
String argu = ".";
if (ictclas.ICTCLAS_Init(argu.getBytes("GB2312")) == false) {
System.out.println("Init Fail!");
return false;
} else
return true;
}
public int importUserDict(String userDict) throws UnsupportedEncodingException {
if (available) {
int nCount = ictclas.ICTCLAS_ImportUserDict(userDict
.getBytes("GB2312"));
return nCount;
} else
return 0;
}
//分词
public String split(String str, int tag) throws IOException {
if (available) {
String string;
byte[] bytes = ictclas.ICTCLAS_ParagraphProcess(str
.getBytes("GB2312"), tag);
string = new String(bytes, 0, bytes.length, "GB2312");
return string.trim();
} else
return null;
}
//退出
public void exit() {
ictclas.ICTCLAS_Exit();
}
}
我们在写一个测试的类Main.java:
package ICTCLAS.kevin.zhang;
//分词器调用测试类
import java.io.IOException;
public class Main {
public static void main(String args[]) throws IOException{
String s = "武汉大学校长顾海良" +
"说武大梅园的风景很美,其实我就住在梅园!";
//ICTCLAS2010 ictclas = new ICTCLAS2010();
Splitter splitter = new Splitter();
int n = splitter.importUserDict("userDic.txt");
System.out.println("用户词典数量:"+n);
String ss = splitter.split(s, 1).trim();
System.out.println("分词结果:"+ss);
String[] array = ss.split("\\s");
for(String en : array){
System.out.println(en);
}
}
}
程序的运行结果:
用户词典数量:4
分词结果:武汉大学/nt 校长/n 顾海良/nr 说/v 武大/n 梅园/ns 的/ude1 风景/n 很/d 美/a ,/wd 其实/d 我/rr 就/d 住/vi 在/p 梅园/ns !/wt
武汉大学/nt
校长/n
顾海良/nr
说/v
武大/n
梅园/ns
的/ude1
风景/n
很/d
美/a
,/wd
其实/d
我/rr
就/d
住/vi
在/p
梅园/ns
!/wt
我的用户词典userDic.txt的内容如下:
武汉大学 nt
顾海良 nr
李白 nr
梅园 ns
用户词典的前边词和右边的词性标注用空格分开
大家可以试着把用户自定义词典中的一些词去掉之后,看看分词的结构会有什么不同!
每个词后边的词性标注的符号含义,在刚才下载的文档中的“文档“文件夹下的ICTPOS3.0.doc文件中有详细介绍。如:nt是机构名,nr是人名,ns是地名
本程序的配置文件的内容如下:
<?xmlversion="1.0"encoding="GB2312"?>
<ICTCLAS>
<DataPath>Data</DataPath> //Data文件夹路径
<TagSet>ICTPOS.map</TagSet> //词性标注集映射文件
<UserDict>on</UserDict> //OnUserDictionaryapplied;Off:notapplied;
<UserDictPrior>On</UserDictPrior>
//用户词典优先,Addedin2006-03-16,requiredbyNECOn:用户词典和核心词典中同时有的词汇,用户词典优
//先,本功能不要滥用,如果将核心词典中的词都设置为用户词典,其效果适得其反
<FieldDict>off</FieldDict> //On:FieldDictionaryapplied;Off:notapplied;
<GranularityContorl>off</GranularityContorl>
<Log>On</Log> //On,Off;例如:Off:关闭日志功能;On:打开日志功能
<version>2010</version> //系统版本号
<Modify>2010-1-25</Modify> //系统最近修订时间
<Lexicon>2009-11-27</Lexicon> //词典最近修订时间
<Contact>pipy_zhang@msn.com</Contact> //词典最近修订时间
</ICTCLAS>
以上程序是参考我的一个学长写的代码!使我受益匪浅,非常感谢他!